// Wisp/Page reception static int intif_parse_WisMessage (int fd) { // rewritten by [Yor] struct map_session_data *sd; int i; if (battle_config.etc_log) printf ("intif_parse_wismessage: id: %d, from: %s, to: %s, message: '%s'\n", RFIFOL (fd, 4), RFIFOP (fd, 8), RFIFOP (fd, 32), RFIFOP (fd, 56)); sd = map_nick2sd ((const char *)RFIFOP (fd, 32)); // Searching destination player if (sd != NULL && strcmp (sd->status.name, (const char *)RFIFOP (fd, 32)) == 0) { // exactly same name (inter-server have checked the name before) // if player ignore all if (sd->ignoreAll == 1) intif_wis_replay (RFIFOL (fd, 4), 2); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target else { const char *wisp_source = (const char *)RFIFOP (fd, 8); // speed up // if player ignore the source character for (i = 0; i < (sizeof (sd->ignore) / sizeof (sd->ignore[0])); i++) if (strcmp (sd->ignore[i].name, wisp_source) == 0) { intif_wis_replay (RFIFOL (fd, 4), 2); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target break; } // if source player not found in ignore list if (i == (sizeof (sd->ignore) / sizeof (sd->ignore[0]))) { clif_wis_message (sd->fd, (const char *)RFIFOP (fd, 8), (const char *)RFIFOP (fd, 56), RFIFOW (fd, 2) - 56); intif_wis_replay (RFIFOL (fd, 4), 0); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target } } } else intif_wis_replay (RFIFOL (fd, 4), 1); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target return 0; }
// map server からの通信 // ・1パケットのみ解析すること // ・パケット長データはinter.cにセットしておくこと // ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない // ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない int inter_party_parse_frommap(int fd) { switch(RFIFOW(fd,0)){ case 0x3020: mapif_parse_CreateParty(fd,RFIFOL(fd,2),(char*)RFIFOP(fd,6),(char*)RFIFOP(fd,30),(char*)RFIFOP(fd,54),RFIFOW(fd,70), RFIFOB(fd,72), RFIFOB(fd,73)); break; case 0x3021: mapif_parse_PartyInfo(fd,RFIFOL(fd,2)); break; case 0x3022: mapif_parse_PartyAddMember(fd,RFIFOL(fd,2),RFIFOL(fd,6),(char*)RFIFOP(fd,10),(char*)RFIFOP(fd,34),RFIFOW(fd,50)); break; case 0x3023: mapif_parse_PartyChangeOption(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOW(fd,10),RFIFOW(fd,12)); break; case 0x3024: mapif_parse_PartyLeave(fd,RFIFOL(fd,2),RFIFOL(fd,6)); break; case 0x3025: mapif_parse_PartyChangeMap(fd,RFIFOL(fd,2),RFIFOL(fd,6),(char*)RFIFOP(fd,10),RFIFOB(fd,26),RFIFOW(fd,27)); break; case 0x3026: mapif_parse_BreakParty(fd,RFIFOL(fd,2)); break; case 0x3027: mapif_parse_PartyMessage(fd,RFIFOL(fd,4),RFIFOL(fd,8),(char*)RFIFOP(fd,12),RFIFOW(fd,2)-12); break; case 0x3028: mapif_parse_PartyCheck(fd,RFIFOL(fd,2),RFIFOL(fd,6),(char*)RFIFOP(fd,10)); break; default: return 0; } return 1; }
int mapif_parse_SaveGuildStorage(int fd) { int guild_exist=1; int guild_id; int len; RFIFOHEAD(fd); guild_id=RFIFOL(fd,8); len=RFIFOW(fd,2); if(sizeof(struct guild_storage)!=len-12) { ShowError("inter storage: data size error %d %d\n",sizeof(struct guild_storage),len-12); } else { #if 0 // Again, innodb key checks make the check pointless // Check if guild exists, I may write a function for this later, coz I use it several times. //printf("- Check if guild %d exists\n",g->guild_id); sprintf(tmp_sql, "SELECT count(*) FROM `%s` WHERE `guild_id`='%d'",guild_db, guild_id); if(mysql_query(&mysql_handle, tmp_sql) ) { ShowSQL("DB error - %s\n",mysql_error(&mysql_handle)); ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql); } sql_res = mysql_store_result(&mysql_handle) ; if (sql_res!=NULL && mysql_num_rows(sql_res)>0) { sql_row = mysql_fetch_row(sql_res); guild_exist = atoi (sql_row[0]); //printf("- Check if guild %d exists : %s\n",g->guild_id,((guild_exist==0)?"No":"Yes")); } mysql_free_result(sql_res) ; //resource free #endif if(guild_exist==1) { memcpy(guild_storage_pt,RFIFOP(fd,12),sizeof(struct guild_storage)); guild_storage_tosql(guild_id,guild_storage_pt); mapif_save_guild_storage_ack(fd,RFIFOL(fd,4),guild_id,0); } else mapif_save_guild_storage_ack(fd,RFIFOL(fd,4),guild_id,1); } return 0; }
// ギルドメンバ情報変更通知 static int intif_parse_GuildMemberInfoChanged (int fd) { int type = RFIFOW (fd, 16), guild_id = RFIFOL (fd, 4); int account_id = RFIFOL (fd, 8), char_id = RFIFOL (fd, 12); void *data = RFIFOP (fd, 18); struct guild *g = guild_search (guild_id); int idx, dd = *((int *) data); if (g == NULL) return 0; idx = guild_getindex (g, account_id, char_id); switch (type) { case GMI_POSITION: g->member[idx].position = dd; guild_memberposition_changed (g, idx, dd); break; case GMI_EXP: g->member[idx].exp = dd; break; } return 0; }
static void mapif_parse_Mail_receiver_check(int fd) { char name[NAME_LENGTH], esc_name[NAME_LENGTH * 2 + 1]; uint32 char_id = 0; uint16 class_ = 0, base_level = 0; safestrncpy(name, (char *)RFIFOP(fd,6), NAME_LENGTH); // Try to find the Dest Char by Name Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`base_level` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) Sql_ShowDebug(sql_handle); else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) { char *data; Sql_GetData(sql_handle, 0, &data, NULL); char_id = atoi(data); Sql_GetData(sql_handle, 1, &data, NULL); class_ = atoi(data); Sql_GetData(sql_handle, 2, &data, NULL); base_level = atoi(data); } Sql_FreeResult(sql_handle); mapif_Mail_receiver_send(fd, RFIFOL(fd,2), char_id, class_, base_level, name); }
// ギルド情報 static int intif_parse_GuildInfo (int fd) { if (RFIFOW (fd, 2) == 8) { if (battle_config.error_log) printf ("intif: guild noinfo %d\n", RFIFOL (fd, 4)); guild_recv_noinfo (RFIFOL (fd, 4)); return 0; } // if(battle_config.etc_log) // printf("intif: guild info %d\n",RFIFOL(fd,4)); if (RFIFOW (fd, 2) != sizeof (struct guild) + 4) { if (battle_config.error_log) printf ("intif: guild info : data size error\n %d %d %d", RFIFOL (fd, 4), RFIFOW (fd, 2), sizeof (struct guild) + 4); } guild_recv_info ((struct guild *) RFIFOP (fd, 4)); return 0; }
static void mapif_parse_Mail_send(int fd) { struct mail_message msg; char esc_name[NAME_LENGTH*2+1]; int account_id = 0; if(RFIFOW(fd,2) != 8 + sizeof(struct mail_message)) return; account_id = RFIFOL(fd,4); memcpy(&msg, RFIFOP(fd,8), sizeof(struct mail_message)); // Try to find the Dest Char by Name SQL->EscapeStringLen(sql_handle, esc_name, msg.dest_name, strnlen(msg.dest_name, NAME_LENGTH)); if ( SQL_ERROR == SQL->Query(sql_handle, "SELECT `account_id`, `char_id` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) Sql_ShowDebug(sql_handle); else if ( SQL_SUCCESS == SQL->NextRow(sql_handle) ) { char *data; SQL->GetData(sql_handle, 0, &data, NULL); if (atoi(data) != account_id) { // Cannot send mail to char in the same account SQL->GetData(sql_handle, 1, &data, NULL); msg.dest_id = atoi(data); } } SQL->FreeResult(sql_handle); msg.status = MAIL_NEW; if( msg.dest_id > 0 ) msg.id = mail_savemessage(&msg); mapif_Mail_send(fd, &msg); // notify sender mapif_Mail_new(&msg); // notify recipient }
// ギルド基本情報変更通知 static int intif_parse_GuildBasicInfoChanged (int fd) { int type = RFIFOW (fd, 8), guild_id = RFIFOL (fd, 4); void *data = RFIFOP (fd, 10); struct guild *g = guild_search (guild_id); short dw = *((short *) data); int dd = *((int *) data); if (g == NULL) return 0; switch (type) { case GBI_EXP: g->exp = dd; break; case GBI_GUILDLV: g->guild_lv = dw; break; case GBI_SKILLPOINT: g->skill_point = dd; break; } return 0; }
// ギルド城データ一括受信(初期化時) static int intif_parse_GuildCastleAllDataLoad (int fd) { return guild_castlealldataload (RFIFOW (fd, 2), (struct guild_castle *) RFIFOP (fd, 4)); }
// ギルド告知変更通知 static int intif_parse_GuildNotice (int fd) { guild_notice_changed (RFIFOL (fd, 2), (const char *)RFIFOP (fd, 6), (const char *)RFIFOP (fd, 66)); return 0; }
/*========================================== * Inter Packets *------------------------------------------*/ int inter_homunculus_parse_frommap(int fd) { unsigned short cmd = RFIFOW(fd,0); switch( cmd ) { case 0x3090: mapif_parse_homunculus_create(fd, (int)RFIFOW(fd,2), (int)RFIFOL(fd,4), (struct s_homunculus*)RFIFOP(fd,8)); break; case 0x3091: mapif_parse_homunculus_load (fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); break; case 0x3092: mapif_parse_homunculus_save (fd, (int)RFIFOW(fd,2), (int)RFIFOL(fd,4), (struct s_homunculus*)RFIFOP(fd,8)); break; case 0x3093: mapif_parse_homunculus_delete(fd, (int)RFIFOL(fd,2)); break; case 0x3094: mapif_parse_homunculus_rename(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6), (char*)RFIFOP(fd,10)); break; default: return 0; } return 1; }
/* [Dekamaster/Nightroad] */ void mapif_parse_accinfo(int fd) { int u_fd = RFIFOL(fd,2), aid = RFIFOL(fd,6), castergroup = RFIFOL(fd,10); char query[NAME_LENGTH], query_esq[NAME_LENGTH*2+1]; int account_id; char *data; safestrncpy(query, (char*) RFIFOP(fd,14), NAME_LENGTH); SQL->EscapeString(sql_handle, query_esq, query); account_id = atoi(query); if (account_id < START_ACCOUNT_NUM) { // is string if ( SQL_ERROR == SQL->Query(sql_handle, "SELECT `account_id`,`name`,`class`,`base_level`,`job_level`,`online` FROM `%s` WHERE `name` LIKE '%s' LIMIT 10", char_db, query_esq) || SQL->NumRows(sql_handle) == 0 ) { if( SQL->NumRows(sql_handle) == 0 ) { inter_msg_to_fd(fd, u_fd, aid, "No matches were found for your criteria, '%s'",query); } else { Sql_ShowDebug(sql_handle); inter_msg_to_fd(fd, u_fd, aid, "An error occured, bother your admin about it."); } SQL->FreeResult(sql_handle); return; } else { if( SQL->NumRows(sql_handle) == 1 ) {//we found a perfect match SQL->NextRow(sql_handle); SQL->GetData(sql_handle, 0, &data, NULL); account_id = atoi(data); SQL->FreeResult(sql_handle); } else {// more than one, listing... [Dekamaster/Nightroad] inter_msg_to_fd(fd, u_fd, aid, "Your query returned the following %d results, please be more specific...",(int)SQL->NumRows(sql_handle)); while ( SQL_SUCCESS == SQL->NextRow(sql_handle) ) { int class_; short base_level, job_level, online; char name[NAME_LENGTH]; SQL->GetData(sql_handle, 0, &data, NULL); account_id = atoi(data); SQL->GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); SQL->GetData(sql_handle, 2, &data, NULL); class_ = atoi(data); SQL->GetData(sql_handle, 3, &data, NULL); base_level = atoi(data); SQL->GetData(sql_handle, 4, &data, NULL); job_level = atoi(data); SQL->GetData(sql_handle, 5, &data, NULL); online = atoi(data); inter_msg_to_fd(fd, u_fd, aid, "[AID: %d] %s | %s | Level: %d/%d | %s", account_id, name, job_name(class_), base_level, job_level, online?"Online":"Offline"); } SQL->FreeResult(sql_handle); return; } } } /* it will only get here if we have a single match */ if( account_id ) { char userid[NAME_LENGTH], user_pass[NAME_LENGTH], email[40], last_ip[20], lastlogin[30], pin_code[5], birthdate[11]; short level = -1; int logincount = 0,state = 0; // FIXME: No, this doesn't really look right. We can't, and shouldn't, access the login table from the char server. if ( SQL_ERROR == SQL->Query(sql_handle, "SELECT `userid`, `user_pass`, `email`, `last_ip`, `group_id`, `lastlogin`, `logincount`, `state`,`pincode`,`birthdate` FROM `login` WHERE `account_id` = '%d' LIMIT 1", account_id) || SQL->NumRows(sql_handle) == 0 ) { if( SQL->NumRows(sql_handle) == 0 ) { inter_msg_to_fd(fd, u_fd, aid, "No account with ID '%d' was found.", account_id ); } else { inter_msg_to_fd(fd, u_fd, aid, "An error occured, bother your admin about it."); Sql_ShowDebug(sql_handle); } } else { SQL->NextRow(sql_handle); SQL->GetData(sql_handle, 0, &data, NULL); safestrncpy(userid, data, sizeof(userid)); SQL->GetData(sql_handle, 1, &data, NULL); safestrncpy(user_pass, data, sizeof(user_pass)); SQL->GetData(sql_handle, 2, &data, NULL); safestrncpy(email, data, sizeof(email)); SQL->GetData(sql_handle, 3, &data, NULL); safestrncpy(last_ip, data, sizeof(last_ip)); SQL->GetData(sql_handle, 4, &data, NULL); level = atoi(data); SQL->GetData(sql_handle, 5, &data, NULL); safestrncpy(lastlogin, data, sizeof(lastlogin)); SQL->GetData(sql_handle, 6, &data, NULL); logincount = atoi(data); SQL->GetData(sql_handle, 7, &data, NULL); state = atoi(data); SQL->GetData(sql_handle, 8, &data, NULL); safestrncpy(pin_code, data, sizeof(pin_code)); SQL->GetData(sql_handle, 9, &data, NULL); safestrncpy(birthdate, data, sizeof(birthdate)); } SQL->FreeResult(sql_handle); if (level == -1) return; inter_msg_to_fd(fd, u_fd, aid, "-- Account %d --", account_id ); inter_msg_to_fd(fd, u_fd, aid, "User: %s | GM Group: %d | State: %d", userid, level, state ); if (level < castergroup) { /* only show pass if your gm level is greater than the one you're searching for */ if( strlen(pin_code) ) inter_msg_to_fd(fd, u_fd, aid, "Password: %s (PIN:%s)", user_pass, pin_code ); else inter_msg_to_fd(fd, u_fd, aid, "Password: %s", user_pass ); } inter_msg_to_fd(fd, u_fd, aid, "Account e-mail: %s | Birthdate: %s", email, birthdate); inter_msg_to_fd(fd, u_fd, aid, "Last IP: %s (%s)", last_ip, geoip_getcountry(str2ip(last_ip)) ); inter_msg_to_fd(fd, u_fd, aid, "This user has logged %d times, the last time were at %s", logincount, lastlogin ); inter_msg_to_fd(fd, u_fd, aid, "-- Character Details --" ); if ( SQL_ERROR == SQL->Query(sql_handle, "SELECT `char_id`, `name`, `char_num`, `class`, `base_level`, `job_level`, `online` FROM `%s` WHERE `account_id` = '%d' ORDER BY `char_num` LIMIT %d", char_db, account_id, MAX_CHARS) || SQL->NumRows(sql_handle) == 0 ) { if( SQL->NumRows(sql_handle) == 0 ) inter_msg_to_fd(fd, u_fd, aid,"This account doesn't have characters."); else { inter_msg_to_fd(fd, u_fd, aid,"An error occured, bother your admin about it."); Sql_ShowDebug(sql_handle); } } else { while ( SQL_SUCCESS == SQL->NextRow(sql_handle) ) { int char_id, class_; short char_num, base_level, job_level, online; char name[NAME_LENGTH]; SQL->GetData(sql_handle, 0, &data, NULL); char_id = atoi(data); SQL->GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); SQL->GetData(sql_handle, 2, &data, NULL); char_num = atoi(data); SQL->GetData(sql_handle, 3, &data, NULL); class_ = atoi(data); SQL->GetData(sql_handle, 4, &data, NULL); base_level = atoi(data); SQL->GetData(sql_handle, 5, &data, NULL); job_level = atoi(data); SQL->GetData(sql_handle, 6, &data, NULL); online = atoi(data); inter_msg_to_fd(fd, u_fd, aid, "[Slot/CID: %d/%d] %s | %s | Level: %d/%d | %s", char_num, char_id, name, job_name(class_), base_level, job_level, online?"On":"Off"); } } SQL->FreeResult(sql_handle); } return; }
// Wisp/page request to send int mapif_parse_WisRequest(int fd) { struct WisData* wd; static int wisid = 0; char name[NAME_LENGTH]; char esc_name[NAME_LENGTH*2+1];// escaped name char* data; size_t len; if ( fd <= 0 ) {return 0;} // check if we have a valid fd if (RFIFOW(fd,2)-52 >= sizeof(wd->msg)) { ShowWarning("inter: Wis message size too long.\n"); return 0; } else if (RFIFOW(fd,2)-52 <= 0) { // normaly, impossible, but who knows... ShowError("inter: Wis message doesn't exist.\n"); return 0; } safestrncpy(name, (char*)RFIFOP(fd,28), NAME_LENGTH); //Received name may be too large and not contain \0! [Skotlex] SQL->EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `name` FROM `%s` WHERE `name`='%s'", char_db, esc_name) ) Sql_ShowDebug(sql_handle); // search if character exists before to ask all map-servers if( SQL_SUCCESS != SQL->NextRow(sql_handle) ) { unsigned char buf[27]; WBUFW(buf, 0) = 0x3802; memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target mapif_send(fd, buf, 27); } else {// Character exists. So, ask all map-servers // to be sure of the correct name, rewrite it SQL->GetData(sql_handle, 0, &data, &len); memset(name, 0, NAME_LENGTH); memcpy(name, data, min(len, NAME_LENGTH)); // if source is destination, don't ask other servers. if( strncmp((const char*)RFIFOP(fd,4), name, NAME_LENGTH) == 0 ) { uint8 buf[27]; WBUFW(buf, 0) = 0x3802; memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target mapif_send(fd, buf, 27); } else { CREATE(wd, struct WisData, 1); // Whether the failure of previous wisp/page transmission (timeout) check_ttl_wisdata(); wd->id = ++wisid; wd->fd = fd; wd->len= RFIFOW(fd,2)-52; memcpy(wd->src, RFIFOP(fd, 4), NAME_LENGTH); memcpy(wd->dst, RFIFOP(fd,28), NAME_LENGTH); memcpy(wd->msg, RFIFOP(fd,52), wd->len); wd->tick = timer->gettick(); idb_put(wis_db, wd->id, wd); mapif_wis_message(wd); } } SQL->FreeResult(sql_handle); return 0; }
int mapif_parse_SavePet(int fd) { RFIFOHEAD(fd); mapif->save_pet(fd, RFIFOL(fd, 4), RFIFOP(fd, 8)); return 0; }
static int intif_parse_LoadGuildStorage (int fd) { struct guild_storage *gstor; struct map_session_data *sd; int guild_id; guild_id = RFIFOL (fd, 8); if (guild_id > 0) { gstor = guild2storage (guild_id); if (!gstor) { if (battle_config.error_log) printf ("intif_parse_LoadGuildStorage: error guild_id %d not exist\n", guild_id); return 1; } if (RFIFOW (fd, 2) - 12 != sizeof (struct guild_storage)) { gstor->storage_status = 0; if (battle_config.error_log) printf ("intif_parse_LoadGuildStorage: data size error %d %d\n", RFIFOW (fd, 2) - 12, sizeof (struct guild_storage)); return 1; } sd = map_id2sd (RFIFOL (fd, 4)); if (sd == NULL) { if (battle_config.error_log) printf ("intif_parse_LoadGuildStorage: user not found %d\n", RFIFOL (fd, 4)); return 1; } if (gstor->storage_status == 1) { // Already open.. lets ignore this update if (battle_config.error_log) printf ("intif_parse_LoadGuildStorage: storage received for a client already open (User %d:%d)\n", sd->status.account_id, sd->status.char_id); return 1; } if (gstor->dirty) { // Already have storage, and it has been modified and not saved yet! Exploit! [Skotlex] if (battle_config.error_log) printf ("intif_parse_LoadGuildStorage: received storage for an already modified non-saved storage! (User %d:%d)\n", sd->status.account_id, sd->status.char_id); return 1; } if (battle_config.save_log) printf ("intif_open_guild_storage: %d\n", RFIFOL (fd, 4)); memcpy (gstor, RFIFOP (fd, 12), sizeof (struct guild_storage)); gstor->storage_status = 1; sd->state.storage_flag = 2; clif_guildstorageitemlist (sd, gstor); clif_guildstorageequiplist (sd, gstor); clif_updateguildstorageamount (sd, gstor); } return 0; }
// Wisp/page request to send int mapif_parse_WisRequest(int fd) { struct WisData* wd; static int wisid = 0; char name[NAME_LENGTH], t_name[NAME_LENGTH*2]; //Needs space to allocate names with escaped chars [Skotlex] if ( fd <= 0 ) {return 0;} // check if we have a valid fd if (RFIFOW(fd,2)-52 >= sizeof(wd->msg)) { ShowWarning("inter: Wis message size too long.\n"); return 0; } else if (RFIFOW(fd,2)-52 <= 0) { // normaly, impossible, but who knows... ShowError("inter: Wis message doesn't exist.\n"); return 0; } memcpy(name, RFIFOP(fd,28), NAME_LENGTH); //Received name may be too large and not contain \0! [Skotlex] name[NAME_LENGTH-1]= '\0'; sprintf (tmp_sql, "SELECT `name` FROM `%s` WHERE `name`='%s'", char_db, jstrescapecpy(t_name, name)); if(mysql_query(&mysql_handle, tmp_sql) ) { ShowSQL("DB error - %s\n",mysql_error(&mysql_handle)); ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql); } sql_res = mysql_store_result(&mysql_handle); // search if character exists before to ask all map-servers if (!(sql_row = mysql_fetch_row(sql_res))) { unsigned char buf[27]; WBUFW(buf, 0) = 0x3802; memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target mapif_send(fd, buf, 27); // Character exists. So, ask all map-servers } else { // to be sure of the correct name, rewrite it memset(name, 0, NAME_LENGTH); strncpy(name, sql_row[0], NAME_LENGTH); // if source is destination, don't ask other servers. if (strcmp((char*)RFIFOP(fd,4),name) == 0) { unsigned char buf[27]; WBUFW(buf, 0) = 0x3802; memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target mapif_send(fd, buf, 27); } else { CREATE(wd, struct WisData, 1); // Whether the failure of previous wisp/page transmission (timeout) check_ttl_wisdata(); wd->id = ++wisid; wd->fd = fd; wd->len= RFIFOW(fd,2)-52; memcpy(wd->src, RFIFOP(fd, 4), NAME_LENGTH); memcpy(wd->dst, RFIFOP(fd,28), NAME_LENGTH); memcpy(wd->msg, RFIFOP(fd,52), wd->len); wd->tick = gettick(); numdb_insert(wis_db, wd->id, wd); mapif_wis_message(wd); } } //Freeing ... O.o if(sql_res){ mysql_free_result(sql_res); } return 0; }
//----------------------------------------------------------------- // inter serverからの通信 // エラーがあれば0(false)を返すこと // パケットが処理できれば1,パケット長が足りなければ2を返すこと int intif_parse (int fd) { int packet_len; int cmd = RFIFOW (fd, 0); // パケットのID確認 if (cmd < 0x3800 || cmd >= 0x3800 + (sizeof (packet_len_table) / sizeof (packet_len_table[0])) || packet_len_table[cmd - 0x3800] == 0) { return 0; } // パケットの長さ確認 packet_len = packet_len_table[cmd - 0x3800]; if (packet_len == -1) { if (RFIFOREST (fd) < 4) return 2; packet_len = RFIFOW (fd, 2); } // if(battle_config.etc_log) // printf("intif_parse %d %x %d %d\n",fd,cmd,packet_len,RFIFOREST(fd)); if (RFIFOREST (fd) < packet_len) { return 2; } // 処理分岐 switch (cmd) { case 0x3800: clif_GMmessage (NULL, (const char *)RFIFOP (fd, 4), packet_len - 4, 0); break; case 0x3801: intif_parse_WisMessage (fd); break; case 0x3802: intif_parse_WisEnd (fd); break; case 0x3803: mapif_parse_WisToGM (fd); break; case 0x3804: intif_parse_AccountReg (fd); break; case 0x3810: intif_parse_LoadStorage (fd); break; case 0x3811: intif_parse_SaveStorage (fd); break; case 0x3818: intif_parse_LoadGuildStorage (fd); break; case 0x3819: intif_parse_SaveGuildStorage (fd); break; case 0x3820: intif_parse_PartyCreated (fd); break; case 0x3821: intif_parse_PartyInfo (fd); break; case 0x3822: intif_parse_PartyMemberAdded (fd); break; case 0x3823: intif_parse_PartyOptionChanged (fd); break; case 0x3824: intif_parse_PartyMemberLeaved (fd); break; case 0x3825: intif_parse_PartyMove (fd); break; case 0x3826: intif_parse_PartyBroken (fd); break; case 0x3827: intif_parse_PartyMessage (fd); break; case 0x3830: intif_parse_GuildCreated (fd); break; case 0x3831: intif_parse_GuildInfo (fd); break; case 0x3832: intif_parse_GuildMemberAdded (fd); break; case 0x3834: intif_parse_GuildMemberLeaved (fd); break; case 0x3835: intif_parse_GuildMemberInfoShort (fd); break; case 0x3836: intif_parse_GuildBroken (fd); break; case 0x3837: intif_parse_GuildMessage (fd); break; case 0x3839: intif_parse_GuildBasicInfoChanged (fd); break; case 0x383a: intif_parse_GuildMemberInfoChanged (fd); break; case 0x383b: intif_parse_GuildPosition (fd); break; case 0x383c: intif_parse_GuildSkillUp (fd); break; case 0x383d: intif_parse_GuildAlliance (fd); break; case 0x383e: intif_parse_GuildNotice (fd); break; case 0x383f: intif_parse_GuildEmblem (fd); break; case 0x3840: intif_parse_GuildCastleDataLoad (fd); break; case 0x3841: intif_parse_GuildCastleDataSave (fd); break; case 0x3842: intif_parse_GuildCastleAllDataLoad (fd); break; //case 0x3880: intif_parse_CreateP.et(fd); break; //case 0x3881: intif_parse_RecvP.etData(fd); break; //case 0x3882: intif_parse_SaveP.etOk(fd); break; //case 0x3883: intif_parse_DeleteP.etOk(fd); break; default: if (battle_config.error_log) printf ("intif_parse : unknown packet %d %x\n", fd, RFIFOW (fd, 0)); return 0; } // パケット読み飛ばし RFIFOSKIP (fd, packet_len); return 1; }
// GM message sending int mapif_parse_GMmessage(int fd) { mapif_GMmessage(RFIFOP(fd, 8), RFIFOW(fd, 2), RFIFOL(fd, 4), fd); return 0; }
/*========================================== * Auth confirmation ack *------------------------------------------*/ void chrif_authok(int fd) { int account_id, group_id, char_id; uint32 login_id1,login_id2; time_t expiration_time; struct mmo_charstatus* status; struct auth_node *node; bool changing_mapservers; TBL_PC* sd; //Check if both servers agree on the struct's size if( RFIFOW(fd,2) - 25 != sizeof(struct mmo_charstatus) ) { ShowError("chrif_authok: Data size mismatch! %d != %d\n", RFIFOW(fd,2) - 25, sizeof(struct mmo_charstatus)); return; } account_id = RFIFOL(fd,4); login_id1 = RFIFOL(fd,8); login_id2 = RFIFOL(fd,12); expiration_time = (time_t)(int32)RFIFOL(fd,16); group_id = RFIFOL(fd,20); changing_mapservers = (RFIFOB(fd,24)); status = (struct mmo_charstatus*)RFIFOP(fd,25); char_id = status->char_id; //Check if we don't already have player data in our server //Causes problems if the currently connected player tries to quit or this data belongs to an already connected player which is trying to re-auth. if ( ( sd = map_id2sd(account_id) ) != NULL ) return; if ( ( node = chrif_search(account_id) ) == NULL ) return; // should not happen if ( node->state != ST_LOGIN ) return; //character in logout phase, do not touch that data. if ( node->sd == NULL ) { /* //When we receive double login info and the client has not connected yet, //discard the older one and keep the new one. chrif_auth_delete(node->account_id, node->char_id, ST_LOGIN); */ return; // should not happen } sd = node->sd; if( runflag == MAPSERVER_ST_RUNNING && node->char_dat == NULL && node->account_id == account_id && node->char_id == char_id && node->login_id1 == login_id1 ) { //Auth Ok if (pc_authok(sd, login_id2, expiration_time, group_id, status, changing_mapservers)) return; } else { //Auth Failed pc_authfail(sd); } chrif_char_offline(sd); //Set him offline, the char server likely has it set as online already. chrif_auth_delete(account_id, char_id, ST_LOGIN); }
/*========================================== * *------------------------------------------*/ int chrif_parse(int fd) { int packet_len, cmd; // only process data from the char-server if ( fd != char_fd ) { ShowDebug("chrif_parse: Disconnecting invalid session #%d (is not the char-server)\n", fd); do_close(fd); return 0; } if ( session[fd]->flag.eof ) { do_close(fd); char_fd = -1; chrif_on_disconnect(); return 0; } else if ( session[fd]->flag.ping ) {/* we've reached stall time */ if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */ set_eof(fd); return 0; } else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */ chrif_keepalive(fd); session[fd]->flag.ping = 2; } } while ( RFIFOREST(fd) >= 2 ) { cmd = RFIFOW(fd,0); if (cmd < 0x2af8 || cmd >= 0x2af8 + ARRAYLENGTH(packet_len_table) || packet_len_table[cmd-0x2af8] == 0) { int r = intif_parse(fd); // Passed on to the intif if (r == 1) continue; // Treated in intif if (r == 2) return 0; // Didn't have enough data (len==-1) ShowWarning("chrif_parse: session #%d, intif_parse failed (unrecognized command 0x%.4x).\n", fd, cmd); set_eof(fd); return 0; } if ( ( packet_len = packet_len_table[cmd-0x2af8] ) == -1) { // dynamic-length packet, second WORD holds the length if (RFIFOREST(fd) < 4) return 0; packet_len = RFIFOW(fd,2); } if ((int)RFIFOREST(fd) < packet_len) return 0; //ShowDebug("Received packet 0x%4x (%d bytes) from char-server (connection %d)\n", RFIFOW(fd,0), packet_len, fd); switch(cmd) { case 0x2af9: chrif_connectack(fd); break; case 0x2afb: chrif_sendmapack(fd); break; case 0x2afd: chrif_authok(fd); break; case 0x2b00: map_setusers(RFIFOL(fd,2)); chrif_keepalive(fd); break; case 0x2b03: clif->charselectok(RFIFOL(fd,2), RFIFOB(fd,6)); break; case 0x2b04: chrif_recvmap(fd); break; case 0x2b06: chrif_changemapserverack(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOW(fd,18), RFIFOW(fd,20), RFIFOW(fd,22), RFIFOL(fd,24), RFIFOW(fd,28)); break; case 0x2b09: map_addnickdb(RFIFOL(fd,2), (char*)RFIFOP(fd,6)); break; case 0x2b0a: socket_datasync(fd, false); break; case 0x2b0d: chrif_changedsex(fd); break; case 0x2b0f: chrif_char_ask_name_answer(RFIFOL(fd,2), (char*)RFIFOP(fd,6), RFIFOW(fd,30), RFIFOW(fd,32)); break; case 0x2b12: chrif_divorceack(RFIFOL(fd,2), RFIFOL(fd,6)); break; case 0x2b14: chrif_accountban(fd); break; case 0x2b1b: chrif_recvfamelist(fd); break; case 0x2b1d: chrif_load_scdata(fd); break; case 0x2b1e: chrif_update_ip(fd); break; case 0x2b1f: chrif_disconnectplayer(fd); break; case 0x2b20: chrif_removemap(fd); break; case 0x2b21: chrif_save_ack(fd); break; case 0x2b22: chrif_updatefamelist_ack(fd); break; case 0x2b24: chrif_keepalive_ack(fd); break; case 0x2b25: chrif_deadopt(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; case 0x2b27: chrif_authfail(fd); break; default: ShowError("chrif_parse : unknown packet (session #%d): 0x%x. Disconnecting.\n", fd, cmd); set_eof(fd); return 0; } if ( fd == char_fd ) //There's the slight chance we lost the connection during parse, in which case this would segfault if not checked [Skotlex] RFIFOSKIP(fd, packet_len); } return 0; }
// 傭兵のデータ受信&保存 int mapif_parse_SaveMerc(int fd) { mapif_save_merc(fd,RFIFOL(fd,4),(struct mmo_mercstatus *)RFIFOP(fd,8)); return 0; }
// 0x7944 - request account id lookup by name (response: 0x7945) // 0x7946 - request account name lookup by id (response: 0x7947) // 0x7952 - request account information lookup by name (response: 0x7953) // 0x7954 - request account information lookup by id (response: 0x7953) //--------------------------------------- int parse_admin(int fd) { unsigned int i, j; char* account_name; struct mmo_account acc; uint32 ipl = session[fd]->client_addr; char ip[16]; ip2str(ipl, ip); if( session[fd]->flag.eof ) { do_close(fd); ShowInfo("Remote administration has disconnected (session #%d).\n", fd); return 0; } while( RFIFOREST(fd) >= 2 ) { uint16 command = RFIFOW(fd,0); switch( command ) { case 0x7530: // Request of the server version ShowStatus("'ladmin': Sending of the server version (ip: %s)\n", ip); WFIFOHEAD(fd,10); WFIFOW(fd,0) = 0x7531; WFIFOB(fd,2) = ATHENA_MAJOR_VERSION; WFIFOB(fd,3) = ATHENA_MINOR_VERSION; WFIFOB(fd,4) = ATHENA_REVISION; WFIFOB(fd,5) = ATHENA_RELEASE_FLAG; WFIFOB(fd,6) = ATHENA_OFFICIAL_FLAG; WFIFOB(fd,7) = ATHENA_SERVER_LOGIN; WFIFOW(fd,8) = ATHENA_MOD_VERSION; WFIFOSET(fd,10); RFIFOSKIP(fd,2); break; /* case 0x7920: // Request of an accounts list if (RFIFOREST(fd) < 10) return 0; { int st, ed; uint16 len; CREATE_BUFFER(id, int, auth_num); st = RFIFOL(fd,2); ed = RFIFOL(fd,6); RFIFOSKIP(fd,10); WFIFOW(fd,0) = 0x7921; if (st < 0) st = 0; if (ed > END_ACCOUNT_NUM || ed < st || ed <= 0) ed = END_ACCOUNT_NUM; ShowStatus("'ladmin': Sending an accounts list (ask: from %d to %d, ip: %s)\n", st, ed, ip); // Sort before send for(i = 0; i < auth_num; i++) { unsigned int k; id[i] = i; for(j = 0; j < i; j++) { if (auth_dat[id[i]].account_id < auth_dat[id[j]].account_id) { for(k = i; k > j; k--) { id[k] = id[k-1]; } id[j] = i; // id[i] break; } } } // Sending accounts information len = 4; for(i = 0; i < auth_num && len < 30000; i++) { int account_id = auth_dat[id[i]].account_id; // use sorted index if (account_id >= st && account_id <= ed) { j = id[i]; WFIFOL(fd,len) = account_id; WFIFOB(fd,len+4) = (unsigned char)isGM(account_id); memcpy(WFIFOP(fd,len+5), auth_dat[j].userid, 24); WFIFOB(fd,len+29) = auth_dat[j].sex; WFIFOL(fd,len+30) = auth_dat[j].logincount; if (auth_dat[j].state == 0 && auth_dat[j].unban_time != 0) // if no state and banished WFIFOL(fd,len+34) = 7; // 6 = Your are Prohibited to log in until %s else WFIFOL(fd,len+34) = auth_dat[j].state; len += 38; } } WFIFOW(fd,2) = len; WFIFOSET(fd,len); //if (id) free(id); DELETE_BUFFER(id); } break; */ case 0x7930: // Request for an account creation if (RFIFOREST(fd) < 91) return 0; { struct mmo_account ma; safestrncpy(ma.userid, (char*)RFIFOP(fd, 2), sizeof(ma.userid)); safestrncpy(ma.pass, (char*)RFIFOP(fd,26), sizeof(ma.pass)); ma.sex = RFIFOB(fd,50); safestrncpy(ma.email, (char*)RFIFOP(fd,51), sizeof(ma.email)); safestrncpy(ma.lastlogin, "-", sizeof(ma.lastlogin)); ShowNotice("'ladmin': Account creation request (account: %s pass: %s, sex: %c, email: %s, ip: %s)\n", ma.userid, ma.pass, ma.sex, ma.email, ip); WFIFOW(fd,0) = 0x7931; WFIFOL(fd,2) = mmo_auth_new(ma.userid, ma.pass, ma.sex, ip); safestrncpy((char*)WFIFOP(fd,6), ma.userid, 24); WFIFOSET(fd,30); } RFIFOSKIP(fd,91); break; /* case 0x7932: // Request for an account deletion if (RFIFOREST(fd) < 26) return 0; { struct mmo_account acc; char* account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; WFIFOW(fd,0) = 0x7933; if( accounts->load_str(accounts, &acc, account_name) ) { // Char-server is notified of deletion (for characters deletion). unsigned char buf[65535]; WBUFW(buf,0) = 0x2730; WBUFL(buf,2) = acc.account_id; charif_sendallwos(-1, buf, 6); // send answer memcpy(WFIFOP(fd,6), acc.userid, 24); WFIFOL(fd,2) = acc.account_id; // delete account memset(acc.userid, '\0', sizeof(acc.userid)); auth_dat[i].account_id = -1; mmo_auth_sync(); } else { WFIFOL(fd,2) = -1; memcpy(WFIFOP(fd,6), account_name, 24); ShowNotice("'ladmin': Attempt to delete an unknown account (account: %s, ip: %s)\n", account_name, ip); } WFIFOSET(fd,30); } RFIFOSKIP(fd,26); break; */ case 0x7934: // Request to change a password if (RFIFOREST(fd) < 50) return 0; { struct mmo_account acc; char* account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; WFIFOW(fd,0) = 0x7935; if( accounts->load_str(accounts, &acc, account_name) ) { WFIFOL(fd,2) = acc.account_id; safestrncpy((char*)WFIFOP(fd,6), acc.userid, 24); safestrncpy(acc.pass, (char*)RFIFOP(fd,26), 24); ShowNotice("'ladmin': Modification of a password (account: %s, new password: %s, ip: %s)\n", acc.userid, acc.pass, ip); accounts->save(accounts, &acc); } else { WFIFOL(fd,2) = -1; safestrncpy((char*)WFIFOP(fd,6), account_name, 24); ShowNotice("'ladmin': Attempt to modify the password of an unknown account (account: %s, ip: %s)\n", account_name, ip); } WFIFOSET(fd,30); } RFIFOSKIP(fd,50); break; case 0x7936: // Request to modify a state if (RFIFOREST(fd) < 50) return 0; { struct mmo_account acc; char* account_name = (char*)RFIFOP(fd,2); uint32 state = RFIFOL(fd,26); account_name[23] = '\0'; WFIFOW(fd,0) = 0x7937; if( accounts->load_str(accounts, &acc, account_name) ) { memcpy(WFIFOP(fd,6), acc.userid, 24); WFIFOL(fd,2) = acc.account_id; if (acc.state == state) ShowNotice("'ladmin': Modification of a state, but the state of the account already has this value (account: %s, received state: %d, ip: %s)\n", account_name, state, ip); else { ShowNotice("'ladmin': Modification of a state (account: %s, new state: %d, ip: %s)\n", acc.userid, state, ip); if (acc.state == 0) { unsigned char buf[16]; WBUFW(buf,0) = 0x2731; WBUFL(buf,2) = acc.account_id; WBUFB(buf,6) = 0; // 0: change of statut, 1: ban WBUFL(buf,7) = state; // status or final date of a banishment charif_sendallwos(-1, buf, 11); } acc.state = state; accounts->save(accounts, &acc); } } else { ShowNotice("'ladmin': Attempt to modify the state of an unknown account (account: %s, received state: %d, ip: %s)\n", account_name, state, ip); WFIFOL(fd,2) = -1; memcpy(WFIFOP(fd,6), account_name, 24); } WFIFOL(fd,30) = state; WFIFOSET(fd,34); } RFIFOSKIP(fd,50); break; /* case 0x7938: // Request for servers list and # of online players { uint8 server_num = 0; ShowStatus("'ladmin': Sending of servers list (ip: %s)\n", ip); for(i = 0; i < MAX_SERVERS; i++) { if (server[i].fd >= 0) { WFIFOL(fd,4+server_num*32) = htonl(server[i].ip); WFIFOW(fd,4+server_num*32+4) = htons(server[i].port); memcpy(WFIFOP(fd,4+server_num*32+6), server[i].name, 20); WFIFOW(fd,4+server_num*32+26) = server[i].users; WFIFOW(fd,4+server_num*32+28) = server[i].maintenance; WFIFOW(fd,4+server_num*32+30) = server[i].new_; server_num++; } } WFIFOW(fd,0) = 0x7939; WFIFOW(fd,2) = 4 + 32 * server_num; WFIFOSET(fd,4+32*server_num); RFIFOSKIP(fd,2); break; } case 0x793a: // Request to password check if (RFIFOREST(fd) < 50) return 0; WFIFOW(fd,0) = 0x793b; WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); if( accounts->load_str(accounts, &acc, account_name) ) { char pass[25]; memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); memcpy(pass, RFIFOP(fd,26), 24); pass[24] = '\0'; remove_control_chars(pass); if (strcmp(acc.pass, pass) == 0) { WFIFOL(fd,2) = acc.account_id; ShowNotice("'ladmin': Check of password OK (account: %s, password: %s, ip: %s)\n", acc.userid, acc.pass, ip); } else { ShowNotice("'ladmin': Failure of password check (account: %s, proposed pass: %s, ip: %s)\n", acc.userid, pass, ip); } } else { memcpy(WFIFOP(fd,6), account_name, 24); ShowNotice("'ladmin': Attempt to check the password of an unknown account (account: %s, ip: %s)\n", account_name, ip); } WFIFOSET(fd,30); RFIFOSKIP(fd,50); break; case 0x793c: // Request to modify sex if (RFIFOREST(fd) < 27) return 0; WFIFOW(fd,0) = 0x793d; WFIFOL(fd,2) = 0xFFFFFFFF; // -1 account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); memcpy(WFIFOP(fd,6), account_name, 24); { char sex; sex = RFIFOB(fd,26); if (sex != 'F' && sex != 'M') { if (sex > 31) ShowNotice("'ladmin': Attempt to give an invalid sex (account: %s, received sex: %c, ip: %s)\n", account_name, sex, ip); else ShowNotice("'ladmin': Attempt to give an invalid sex (account: %s, received sex: 'control char', ip: %s)\n", account_name, ip); } else { if( accounts->load_str(accounts, &acc, account_name) ) { memcpy(WFIFOP(fd,6), acc.userid, 24); if (acc.sex != sex) { unsigned char buf[16]; ShowNotice("'ladmin': Modification of a sex (account: %s, new sex: %c, ip: %s)\n", acc.userid, sex, ip); WFIFOL(fd,2) = acc.account_id; acc.sex = sex; accounts->save(accounts, &acc); // send to all char-server the change WBUFW(buf,0) = 0x2723; WBUFL(buf,2) = acc.account_id; WBUFB(buf,6) = acc.sex; charif_sendallwos(-1, buf, 7); } else { ShowNotice("'ladmin': Modification of a sex, but the sex is already the good sex (account: %s, sex: %c, ip: %s)\n", acc.userid, sex, ip); } } else { ShowNotice("'ladmin': Attempt to modify the sex of an unknown account (account: %s, received sex: %c, ip: %s)\n", account_name, sex, ip); } } } WFIFOSET(fd,30); RFIFOSKIP(fd,27); break; case 0x793e: // Request to modify GM level if (RFIFOREST(fd) < 27) return 0; WFIFOW(fd,0) = 0x793f; WFIFOL(fd,2) = 0xFFFFFFFF; // -1 account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); memcpy(WFIFOP(fd,6), account_name, 24); { char new_gm_level; new_gm_level = RFIFOB(fd,26); if( new_gm_level < 0 || new_gm_level > 99 ) ShowNotice("'ladmin': Attempt to give an invalid GM level (account: %s, received GM level: %d, ip: %s)\n", account_name, (int)new_gm_level, ip); else if( !accounts->load_str(accounts, &acc, account_name) ) ShowNotice("'ladmin': Attempt to modify the GM level of an unknown account (account: %s, received GM level: %d, ip: %s)\n", account_name, (int)new_gm_level, ip); else { memcpy(WFIFOP(fd,6), acc.userid, 24); if (isGM(acc.account_id) == new_gm_level) ShowNotice("'ladmin': Attempt to modify of a GM level, but the GM level is already the good GM level (account: %s (%d), GM level: %d, ip: %s)\n", acc.userid, acc.account_id, (int)new_gm_level, ip); else { //TODO: change level } } } WFIFOSET(fd,30); RFIFOSKIP(fd,27); break; case 0x7940: // Request to modify e-mail if (RFIFOREST(fd) < 66) return 0; WFIFOW(fd,0) = 0x7941; WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); memcpy(WFIFOP(fd,6), account_name, 24); { char email[40]; memcpy(email, RFIFOP(fd,26), 40); if (e_mail_check(email) == 0) { ShowNotice("'ladmin': Attempt to give an invalid e-mail (account: %s, ip: %s)\n", account_name, ip); } else { remove_control_chars(email); i = search_account_index(account_name); if (i != -1) { memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); memcpy(auth_dat[i].email, email, 40); WFIFOL(fd,2) = auth_dat[i].account_id; ShowNotice("'ladmin': Modification of an email (account: %s, new e-mail: %s, ip: %s)\n", auth_dat[i].userid, email, ip); mmo_auth_sync(); } else { ShowNotice("'ladmin': Attempt to modify the e-mail of an unknown account (account: %s, received e-mail: %s, ip: %s)\n", account_name, email, ip); } } } WFIFOSET(fd,30); RFIFOSKIP(fd,66); break; case 0x7942: // Request to modify memo field if ((int)RFIFOREST(fd) < 28 || (int)RFIFOREST(fd) < (28 + RFIFOW(fd,26))) return 0; WFIFOW(fd,0) = 0x7943; WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); i = search_account_index(account_name); if (i != -1) { int size_of_memo = sizeof(auth_dat[i].memo); memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); memset(auth_dat[i].memo, '\0', size_of_memo); if (RFIFOW(fd,26) == 0) { strncpy(auth_dat[i].memo, "-", size_of_memo); } else if (RFIFOW(fd,26) > size_of_memo - 1) { memcpy(auth_dat[i].memo, RFIFOP(fd,28), size_of_memo - 1); } else { memcpy(auth_dat[i].memo, RFIFOP(fd,28), RFIFOW(fd,26)); } auth_dat[i].memo[size_of_memo - 1] = '\0'; remove_control_chars(auth_dat[i].memo); WFIFOL(fd,2) = auth_dat[i].account_id; ShowNotice("'ladmin': Modification of a memo field (account: %s, new memo: %s, ip: %s)\n", auth_dat[i].userid, auth_dat[i].memo, ip); mmo_auth_sync(); } else { memcpy(WFIFOP(fd,6), account_name, 24); ShowNotice("'ladmin': Attempt to modify the memo field of an unknown account (account: %s, ip: %s)\n", account_name, ip); } WFIFOSET(fd,30); RFIFOSKIP(fd,28 + RFIFOW(fd,26)); break; case 0x7944: // Request to found an account id if (RFIFOREST(fd) < 26) return 0; WFIFOW(fd,0) = 0x7945; WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); i = search_account_index(account_name); if (i != -1) { memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); WFIFOL(fd,2) = auth_dat[i].account_id; ShowNotice("'ladmin': Request (by the name) of an account id (account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, auth_dat[i].account_id, ip); } else { memcpy(WFIFOP(fd,6), account_name, 24); ShowNotice("'ladmin': ID request (by the name) of an unknown account (account: %s, ip: %s)\n", account_name, ip); } WFIFOSET(fd,30); RFIFOSKIP(fd,26); break; case 0x7946: // Request to found an account name if (RFIFOREST(fd) < 6) return 0; WFIFOW(fd,0) = 0x7947; WFIFOL(fd,2) = RFIFOL(fd,2); memset(WFIFOP(fd,6), '\0', 24); for(i = 0; i < auth_num; i++) { if (auth_dat[i].account_id == (int)RFIFOL(fd,2)) { strncpy((char*)WFIFOP(fd,6), auth_dat[i].userid, 24); ShowNotice("'ladmin': Request (by id) of an account name (account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, RFIFOL(fd,2), ip); break; } } if (i == auth_num) { ShowNotice("'ladmin': Name request (by id) of an unknown account (id: %d, ip: %s)\n", RFIFOL(fd,2), ip); strncpy((char*)WFIFOP(fd,6), "", 24); } WFIFOSET(fd,30); RFIFOSKIP(fd,6); break; case 0x7948: // Request to change the validity limit (timestamp) (absolute value) if (RFIFOREST(fd) < 30) return 0; { time_t timestamp; char tmpstr[2048]; WFIFOW(fd,0) = 0x7949; WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); timestamp = (time_t)RFIFOL(fd,26); strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); i = search_account_index(account_name); if (i != -1) { memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); ShowNotice("'ladmin': Change of a validity limit (account: %s, new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, timestamp, (timestamp == 0 ? "unlimited" : tmpstr), ip); auth_dat[i].expiration_time = timestamp; WFIFOL(fd,2) = auth_dat[i].account_id; mmo_auth_sync(); } else { memcpy(WFIFOP(fd,6), account_name, 24); ShowNotice("'ladmin': Attempt to change the validity limit of an unknown account (account: %s, received validity: %d (%s), ip: %s)\n", account_name, timestamp, (timestamp == 0 ? "unlimited" : tmpstr), ip); } WFIFOL(fd,30) = (unsigned int)timestamp; } WFIFOSET(fd,34); RFIFOSKIP(fd,30); break; case 0x794a: // Request to change the final date of a banishment (timestamp) (absolute value) if (RFIFOREST(fd) < 30) return 0; { time_t timestamp; char tmpstr[2048]; WFIFOW(fd,0) = 0x794b; WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); timestamp = (time_t)RFIFOL(fd,26); if (timestamp <= time(NULL)) timestamp = 0; strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); i = search_account_index(account_name); if (i != -1) { memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); WFIFOL(fd,2) = auth_dat[i].account_id; ShowNotice("'ladmin': Change of the final date of a banishment (account: %s, new final date of banishment: %d (%s), ip: %s)\n", auth_dat[i].userid, timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip); if (auth_dat[i].unban_time != timestamp) { if (timestamp != 0) { unsigned char buf[16]; WBUFW(buf,0) = 0x2731; WBUFL(buf,2) = auth_dat[i].account_id; WBUFB(buf,6) = 1; // 0: change of statut, 1: ban WBUFL(buf,7) = (unsigned int)timestamp; // status or final date of a banishment charif_sendallwos(-1, buf, 11); } auth_dat[i].unban_time = timestamp; mmo_auth_sync(); } } else { memcpy(WFIFOP(fd,6), account_name, 24); ShowNotice("'ladmin': Attempt to change the final date of a banishment of an unknown account (account: %s, received final date of banishment: %d (%s), ip: %s)\n", account_name, timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip); } WFIFOL(fd,30) = (unsigned int)timestamp; } WFIFOSET(fd,34); RFIFOSKIP(fd,30); break; case 0x794c: // Request to change the final date of a banishment (timestamp) (relative change) if (RFIFOREST(fd) < 38) return 0; { time_t timestamp; struct tm *tmtime; char tmpstr[2048]; WFIFOW(fd,0) = 0x794d; WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); i = search_account_index(account_name); if (i != -1) { WFIFOL(fd,2) = auth_dat[i].account_id; memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); if (auth_dat[i].unban_time == 0 || auth_dat[i].unban_time < time(NULL)) timestamp = time(NULL); else timestamp = auth_dat[i].unban_time; tmtime = localtime(×tamp); tmtime->tm_year = tmtime->tm_year + (short)RFIFOW(fd,26); tmtime->tm_mon = tmtime->tm_mon + (short)RFIFOW(fd,28); tmtime->tm_mday = tmtime->tm_mday + (short)RFIFOW(fd,30); tmtime->tm_hour = tmtime->tm_hour + (short)RFIFOW(fd,32); tmtime->tm_min = tmtime->tm_min + (short)RFIFOW(fd,34); tmtime->tm_sec = tmtime->tm_sec + (short)RFIFOW(fd,36); timestamp = mktime(tmtime); if (timestamp != -1) { if (timestamp <= time(NULL)) timestamp = 0; strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); ShowNotice("'ladmin': Adjustment of a final date of a banishment (account: %s, (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip); if (auth_dat[i].unban_time != timestamp) { if (timestamp != 0) { unsigned char buf[16]; WBUFW(buf,0) = 0x2731; WBUFL(buf,2) = auth_dat[i].account_id; WBUFB(buf,6) = 1; // 0: change of statut, 1: ban WBUFL(buf,7) = (unsigned int)timestamp; // status or final date of a banishment charif_sendallwos(-1, buf, 11); } auth_dat[i].unban_time = timestamp; mmo_auth_sync(); } } else { strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].unban_time)); ShowNotice("'ladmin': Impossible to adjust the final date of a banishment (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", auth_dat[i].userid, auth_dat[i].unban_time, (auth_dat[i].unban_time == 0 ? "no banishment" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), ip); } WFIFOL(fd,30) = (unsigned long)auth_dat[i].unban_time; } else { memcpy(WFIFOP(fd,6), account_name, 24); ShowNotice("'ladmin': Attempt to adjust the final date of a banishment of an unknown account (account: %s, ip: %s)\n", account_name, ip); WFIFOL(fd,30) = 0; } } WFIFOSET(fd,34); RFIFOSKIP(fd,38); break; case 0x794e: // Request to send a broadcast message if (RFIFOREST(fd) < 8 || RFIFOREST(fd) < (8 + RFIFOL(fd,4))) return 0; WFIFOW(fd,0) = 0x794f; WFIFOW(fd,2) = 0xFFFF; // WTF??? if (RFIFOL(fd,4) < 1) { ShowNotice("'ladmin': Receiving a message for broadcast, but message is void (ip: %s)\n", ip); } else { // at least 1 char-server for(i = 0; i < MAX_SERVERS; i++) if (server[i].fd >= 0) break; if (i == MAX_SERVERS) { ShowNotice("'ladmin': Receiving a message for broadcast, but no char-server is online (ip: %s)\n", ip); } else { unsigned char buf[32000]; char message[32000]; WFIFOW(fd,2) = 0; memset(message, '\0', sizeof(message)); memcpy(message, RFIFOP(fd,8), RFIFOL(fd,4)); message[sizeof(message)-1] = '\0'; remove_control_chars(message); if (RFIFOW(fd,2) == 0) ShowNotice("'ladmin': Receiving a message for broadcast (message (in yellow): %s, ip: %s)\n", message, ip); else ShowNotice("'ladmin': Receiving a message for broadcast (message (in blue): %s, ip: %s)\n", message, ip); // send same message to all char-servers (no answer) memcpy(WBUFP(buf,0), RFIFOP(fd,0), 8 + RFIFOL(fd,4)); WBUFW(buf,0) = 0x2726; charif_sendallwos(-1, buf, 8 + RFIFOL(fd,4)); } } WFIFOSET(fd,4); RFIFOSKIP(fd,8 + RFIFOL(fd,4)); break; case 0x7950: // Request to change the validity limite (timestamp) (relative change) if (RFIFOREST(fd) < 38) return 0; { time_t timestamp; struct tm *tmtime; char tmpstr[2048]; char tmpstr2[2048]; WFIFOW(fd,0) = 0x7951; WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; remove_control_chars(account_name); i = search_account_index(account_name); if (i != -1) { WFIFOL(fd,2) = auth_dat[i].account_id; memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); timestamp = auth_dat[i].expiration_time; if (timestamp == 0 || timestamp < time(NULL)) timestamp = time(NULL); tmtime = localtime(×tamp); tmtime->tm_year = tmtime->tm_year + (short)RFIFOW(fd,26); tmtime->tm_mon = tmtime->tm_mon + (short)RFIFOW(fd,28); tmtime->tm_mday = tmtime->tm_mday + (short)RFIFOW(fd,30); tmtime->tm_hour = tmtime->tm_hour + (short)RFIFOW(fd,32); tmtime->tm_min = tmtime->tm_min + (short)RFIFOW(fd,34); tmtime->tm_sec = tmtime->tm_sec + (short)RFIFOW(fd,36); timestamp = mktime(tmtime); if (timestamp != -1) { strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].expiration_time)); strftime(tmpstr2, 24, login_config.date_format, localtime(×tamp)); ShowNotice("'ladmin': Adjustment of a validity limit (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, auth_dat[i].expiration_time, (auth_dat[i].expiration_time == 0 ? "unlimited" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), timestamp, (timestamp == 0 ? "unlimited" : tmpstr2), ip); auth_dat[i].expiration_time = timestamp; mmo_auth_sync(); WFIFOL(fd,30) = (unsigned long)auth_dat[i].expiration_time; } else { strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].expiration_time)); ShowNotice("'ladmin': Impossible to adjust a validity limit (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", auth_dat[i].userid, auth_dat[i].expiration_time, (auth_dat[i].expiration_time == 0 ? "unlimited" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), ip); WFIFOL(fd,30) = 0; } } else { memcpy(WFIFOP(fd,6), account_name, 24); ShowNotice("'ladmin': Attempt to adjust the validity limit of an unknown account (account: %s, ip: %s)\n", account_name, ip); WFIFOL(fd,30) = 0; } WFIFOSET(fd,34); } RFIFOSKIP(fd,38); break; */ case 0x7952: // Request about informations of an account (by account name) if (RFIFOREST(fd) < 26) return 0; { struct mmo_account acc; WFIFOW(fd,0) = 0x7953; account_name = (char*)RFIFOP(fd,2); account_name[23] = '\0'; if( accounts->load_str(accounts, &acc, account_name) ) { ShowNotice("'ladmin': Sending information of an account (request by the name; account: %s, id: %d, ip: %s)\n", acc.userid, acc.account_id, ip); WFIFOL(fd,2) = acc.account_id; WFIFOB(fd,6) = acc.level; safestrncpy((char*)WFIFOP(fd,7), acc.userid, 24); WFIFOB(fd,31) = acc.sex; WFIFOL(fd,32) = acc.logincount; WFIFOL(fd,36) = acc.state; safestrncpy((char*)WFIFOP(fd,40), "-", 20); // error message (removed) safestrncpy((char*)WFIFOP(fd,60), acc.lastlogin, 24); safestrncpy((char*)WFIFOP(fd,84), acc.last_ip, 16); safestrncpy((char*)WFIFOP(fd,100), acc.email, 40); WFIFOL(fd,140) = (unsigned long)acc.expiration_time; WFIFOL(fd,144) = (unsigned long)acc.unban_time; WFIFOW(fd,148) = 0; // previously, this was strlen(memo), and memo went afterwards } else { ShowNotice("'ladmin': Attempt to obtain information (by the name) of an unknown account (account: %s, ip: %s)\n", account_name, ip); WFIFOL(fd,2) = -1; safestrncpy((char*)WFIFOP(fd,7), account_name, 24); // not found } WFIFOSET(fd,150); } RFIFOSKIP(fd,26); break; case 0x7954: // Request about information of an account (by account id) if (RFIFOREST(fd) < 6) return 0; { struct mmo_account acc; int account_id = RFIFOL(fd,2); WFIFOHEAD(fd,150); WFIFOW(fd,0) = 0x7953; WFIFOL(fd,2) = account_id; if( accounts->load_num(accounts, &acc, account_id) ) { ShowNotice("'ladmin': Sending information of an account (request by the id; account: %s, id: %d, ip: %s)\n", acc.userid, account_id, ip); WFIFOB(fd,6) = acc.level; safestrncpy((char*)WFIFOP(fd,7), acc.userid, 24); WFIFOB(fd,31) = acc.sex; WFIFOL(fd,32) = acc.logincount; WFIFOL(fd,36) = acc.state; safestrncpy((char*)WFIFOP(fd,40), "-", 20); // error message (removed) safestrncpy((char*)WFIFOP(fd,60), acc.lastlogin, 24); safestrncpy((char*)WFIFOP(fd,84), acc.last_ip, 16); safestrncpy((char*)WFIFOP(fd,100), acc.email, 40); WFIFOL(fd,140) = (unsigned long)acc.expiration_time; WFIFOL(fd,144) = (unsigned long)acc.unban_time; WFIFOW(fd,148) = 0; // previously, this was strlen(memo), and memo went afterwards } else { ShowNotice("'ladmin': Attempt to obtain information (by the id) of an unknown account (id: %d, ip: %s)\n", account_id, ip); safestrncpy((char*)WFIFOP(fd,7), "", 24); // not found } WFIFOSET(fd,150); } RFIFOSKIP(fd,6); break; default: ShowStatus("'ladmin': End of connection, unknown packet (ip: %s)\n", ip); set_eof(fd); return 0; } } RFIFOSKIP(fd,RFIFOREST(fd)); return 0; }
/*! * \brief Parse from Client * * \author Fimbulwinter Development Team * \author GreenBox * \date 08/12/11 * **/ int CharServer::parse_from_client(tcp_connection::pointer cl) { CharSessionData *csd = ((CharSessionData *)cl->get_data()); if (cl->flags.eof) { if (csd && csd->auth && auth_conn_ok) { WFIFOHEAD(auth_conn,6); WFIFOW(auth_conn,0) = INTER_CA_SET_ACC_OFF; WFIFOL(auth_conn,2) = csd->account_id; auth_conn->send_buffer(6); } set_char_offline(csd->account_id, -1); if (csd) delete csd; ShowInfo("Closed connection from '"CL_WHITE"%s"CL_RESET"'.\n", cl->socket().remote_endpoint().address().to_string().c_str()); cl->do_close(); return 0; } while(RFIFOREST(cl) >= 2) { unsigned short cmd = RFIFOW(cl, 0); #define FIFOSD_CHECK(rest) { if(RFIFOREST(cl) < rest) return 0; if (csd==NULL || !csd->auth) { cl->skip(rest); return 0; } } switch (cmd) { case HEADER_CH_SELECT_CHAR: FIFOSD_CHECK(3); { int slot = RFIFOB(cl,2); int char_id; CharData cd; cl->skip(3); { statement s = (database->prepare << "SELECT `char_id` FROM `char` WHERE `account_id`=:a AND `char_num`=:s", use(csd->account_id), use(slot), into(char_id)); s.execute(true); if (s.get_affected_rows() <= 0) { WFIFOPACKET(cl, spacket, HC_REFUSE_ENTER); spacket->error_code = 0; cl->send_buffer(sizeof(struct PACKET_HC_REFUSE_ENTER)); } } chars->load_char(char_id, cd, true); int server = -1; if (map_to_zone.count(cd.last_point.map)) server = map_to_zone[cd.last_point.map]; if (server < 0) { // TODO: Find for major city WFIFOPACKET(cl, spacket, SC_NOTIFY_BAN); spacket->error_code = 1; cl->send_buffer(sizeof(struct PACKET_SC_NOTIFY_BAN)); break; } auth_nodes[csd->account_id].sex = csd->sex; auth_nodes[csd->account_id].char_id = char_id; auth_nodes[csd->account_id].gmlevel = csd->gmlevel; auth_nodes[csd->account_id].login_id1 = csd->login_id1; auth_nodes[csd->account_id].login_id2 = csd->login_id2; auth_nodes[csd->account_id].expiration_time = csd->expiration_time; WFIFOPACKET(cl, spacket, HC_NOTIFY_ZONESVR); spacket->char_id = char_id; maps.copy_map_name_ext((char*)spacket->map_name, cd.last_point.map); spacket->addr.ip = htonl(servers[server].addr.to_ulong()); spacket->addr.port = servers[server].port; cl->send_buffer(sizeof(struct PACKET_HC_NOTIFY_ZONESVR)); } break; case HEADER_CH_REQUEST_DEL_TIMER: FIFOSD_CHECK(6); delete2_req(cl, csd); cl->skip(6); break; case HEADER_CH_ACCEPT_DEL_REQ: FIFOSD_CHECK(12); delete2_accept(cl, csd); cl->skip(6); break; case HEADER_CH_CANCEL_DEL_REQ: FIFOSD_CHECK(6); delete2_cancel(cl, csd); cl->skip(6); break; case HEADER_CH_DELETE_CHAR: case HEADER_CH_DELETE_CHAR2: if (cmd == HEADER_CH_DELETE_CHAR) FIFOSD_CHECK(sizeof(struct PACKET_CH_DELETE_CHAR)); if (cmd == HEADER_CH_DELETE_CHAR2) FIFOSD_CHECK(sizeof(struct PACKET_CH_DELETE_CHAR2)); { int cid = RFIFOL(cl,2); char email[40]; memcpy(email, RFIFOP(cl,6), 40); cl->skip((cmd == HEADER_CH_DELETE_CHAR) ? sizeof(struct PACKET_CH_DELETE_CHAR) : sizeof(struct PACKET_CH_DELETE_CHAR2)); if (_strcmpi(email, csd->email) != 0 && (strcmp("*****@*****.**", csd->email) || (strcmp("*****@*****.**", email) && strcmp("", email)))) { WFIFOPACKET(cl, spacket, HC_REFUSE_DELETECHAR); spacket->error_code = 0; cl->send_buffer(sizeof(struct PACKET_HC_REFUSE_DELETECHAR)); break; } bool found = false; int i, ch; for (i = 0; i < MAX_CHARS; i++) { if (csd->found_char[i] == cid) { found = true; break; } } if (!found) { WFIFOPACKET(cl, spacket, HC_REFUSE_DELETECHAR); spacket->error_code = 0; cl->send_buffer(sizeof(struct PACKET_HC_REFUSE_DELETECHAR)); break; } else { for(ch = i; ch < MAX_CHARS - 1; ch++) csd->found_char[ch] = csd->found_char[ch+1]; csd->found_char[MAX_CHARS - 1] = -1; if (!chars->delete_char(cid)) { WFIFOPACKET(cl, spacket, HC_REFUSE_DELETECHAR); spacket->error_code = 0; cl->send_buffer(sizeof(struct PACKET_HC_REFUSE_DELETECHAR)); break; } WFIFOPACKET(cl, spacket, HC_ACCEPT_DELETECHAR); cl->send_buffer(sizeof(struct PACKET_HC_ACCEPT_DELETECHAR)); } } break; case HEADER_CH_MAKE_CHAR: FIFOSD_CHECK(sizeof(struct PACKET_CH_MAKE_CHAR)); { TYPECAST_PACKET(RFIFOP(cl,0),rpacket,CH_MAKE_CHAR); // TODO: Check create char disabled int i = create_char(csd, (char*)rpacket->name,rpacket->str,rpacket->agi,rpacket->vit,rpacket->int_,rpacket->dex,rpacket->luk,rpacket->char_slot,rpacket->head_color,rpacket->head_style); //'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3) if (i < 0) { WFIFOPACKET(cl, spacket, HC_REFUSE_MAKECHAR); switch (i) { case -1: spacket->error_code = 0x00; break; case -2: spacket->error_code = 0xFF; break; case -3: spacket->error_code = 0x01; break; } cl->send_buffer(sizeof(struct PACKET_HC_REFUSE_MAKECHAR)); } else { // retrieve data CharData char_dat; memset(&char_dat, 0, sizeof(CharData)); chars->load_char(i, char_dat, false); //Only the short data is needed. // send to player WFIFOPACKET(cl, spacket, HC_ACCEPT_MAKECHAR); char_to_buf(&spacket->charinfo, &char_dat); cl->send_buffer(sizeof(struct PACKET_HC_ACCEPT_MAKECHAR)); // add new entry to the chars list for (int n = 0; n < MAX_CHARS; n++) { if(csd->found_char[n] == -1) csd->found_char[n] = i; // the char_id of the new char } } cl->skip(sizeof(struct PACKET_CH_MAKE_CHAR)); } break; case HEADER_CH_ENTER_CHECKBOT: FIFOSD_CHECK(sizeof(struct PACKET_CH_ENTER_CHECKBOT)); { WFIFOPACKET(cl, spacket, HC_CHECKBOT_RESULT); spacket->packet_len = sizeof(struct PACKET_HC_CHECKBOT_RESULT); spacket->result = 1; cl->send_buffer(spacket->packet_len); cl->skip(TYPECAST_PACKET_ONCE(RFIFOP(cl,0), CH_ENTER_CHECKBOT)->packet_len); } break; case HEADER_CH_CHECKBOT: FIFOSD_CHECK(sizeof(struct PACKET_CH_CHECKBOT)); { WFIFOPACKET(cl, spacket, HC_CHECKBOT_RESULT); spacket->packet_len = sizeof(struct PACKET_HC_CHECKBOT_RESULT); spacket->result = 1; cl->send_buffer(spacket->packet_len); cl->skip(TYPECAST_PACKET_ONCE(RFIFOP(cl,0), CH_CHECKBOT)->packet_len); } break; case HEADER_CH_ENTER: if(RFIFOREST(cl) < sizeof(struct PACKET_CH_ENTER)) return 0; { int account_id = RFIFOL(cl,2); unsigned int login_id1 = RFIFOL(cl,6); unsigned int login_id2 = RFIFOL(cl,10); char sex = RFIFOB(cl,16); cl->skip(sizeof(struct PACKET_CH_ENTER)); if (csd) { break; } csd = new CharSessionData(); csd->account_id = account_id; csd->login_id1 = login_id1; csd->login_id2 = login_id2; csd->sex = sex; csd->auth = false; csd->cl = cl; cl->set_data((char*)csd); WFIFOHEAD(cl, 4); WFIFOL(cl,0) = account_id; cl->send_buffer(4); if (auth_nodes.count(account_id) && auth_nodes[account_id].login_id1 == login_id1 && auth_nodes[account_id].login_id2 == login_id2) { auth_nodes.erase(account_id); auth_ok(cl, csd); } else { if (auth_conn_ok) { WFIFOHEAD(auth_conn,19); WFIFOW(auth_conn,0) = INTER_CA_AUTH; WFIFOL(auth_conn,2) = csd->account_id; WFIFOL(auth_conn,6) = csd->login_id1; WFIFOL(auth_conn,10) = csd->login_id2; WFIFOB(auth_conn,14) = csd->sex; WFIFOL(auth_conn,15) = cl->tag(); auth_conn->send_buffer(19); } else { WFIFOPACKET(cl, spacket, HC_REFUSE_ENTER); spacket->error_code = 0; cl->send_buffer(sizeof(struct PACKET_HC_REFUSE_ENTER)); } } } break; case HEADER_PING: if (RFIFOREST(cl) < sizeof(PACKET_PING)) return 0; cl->skip(sizeof(PACKET_PING)); break; case INTER_ZC_LOGIN: if (RFIFOREST(cl) < 60) return 0; { char *user = (char*)RFIFOP(cl, 2); char *pass = (char*)RFIFOP(cl, 26); if (strcmp(user, config.inter_login_user.c_str()) || strcmp(pass, config.inter_login_pass.c_str())) { WFIFOHEAD(cl, 3); WFIFOW(cl, 0) = INTER_CZ_LOGIN_REPLY; WFIFOB(cl, 2) = 1; cl->send_buffer(3); } else { int id = cl->tag(); servers[id].cl = cl; servers[id].addr = address_v4(ntohl(RFIFOL(cl, 54))); servers[id].port = ntohs(RFIFOW(cl, 58)); servers[id].users = 0; cl->set_parser(&CharServer::parse_from_zone); cl->flags.server = 1; cl->realloc_fifo(FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); WFIFOHEAD(cl, 3); WFIFOW(cl, 0) = INTER_CZ_LOGIN_REPLY; WFIFOB(cl, 2) = 0; cl->send_buffer(3); } cl->skip(60); } break; default: ShowWarning("Unknown packet 0x%04x sent from %s, closing connection.\n", cmd, cl->socket().remote_endpoint().address().to_string().c_str()); cl->set_eof(); return 0; } } return 0; }
int mapif_parse_CreatePet(int fd){ RFIFOHEAD(fd); mapif_create_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOW(fd, 10), RFIFOW(fd, 12), RFIFOW(fd, 14), RFIFOW(fd, 16), RFIFOW(fd, 18), RFIFOW(fd, 20), RFIFOB(fd, 22), RFIFOB(fd, 23), (char*)RFIFOP(fd, 24)); return 0; }
/** * Player requesting to change map-serv * @param fd: wich fd to parse from * @return : 0 not enough data received, 1 success */ int chmapif_parse_reqchangemapserv(int fd){ if (RFIFOREST(fd) < 39) return 0; { int map_id, map_fd = -1; struct mmo_charstatus* char_data; struct mmo_charstatus char_dat; DBMap* char_db_ = char_get_chardb(); map_id = char_search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port. if (map_id >= 0) map_fd = map_server[map_id].fd; //Char should just had been saved before this packet, so this should be safe. [Skotlex] char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14)); if (char_data == NULL) { //Really shouldn't happen. char_mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true); char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14)); } if( runflag == CHARSERVER_ST_RUNNING && session_isActive(map_fd) && char_data ) { //Send the map server the auth of this player. struct online_char_data* data; struct auth_node* node; DBMap* auth_db = char_get_authdb(); DBMap* online_char_db = char_get_onlinedb(); int aid = RFIFOL(fd,2); //Update the "last map" as this is where the player must be spawned on the new map server. char_data->last_point.map = RFIFOW(fd,18); char_data->last_point.x = RFIFOW(fd,20); char_data->last_point.y = RFIFOW(fd,22); char_data->sex = RFIFOB(fd,30); // create temporary auth entry CREATE(node, struct auth_node, 1); node->account_id = aid; node->char_id = RFIFOL(fd,14); node->login_id1 = RFIFOL(fd,6); node->login_id2 = RFIFOL(fd,10); node->sex = RFIFOB(fd,30); node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing) node->ip = ntohl(RFIFOL(fd,31)); node->group_id = RFIFOL(fd,35); node->changing_mapservers = 1; idb_put(auth_db, aid, node); data = idb_ensure(online_char_db, aid, char_create_online_data); data->char_id = char_data->char_id; data->server = map_id; //Update server where char is. //Reply with an ack. WFIFOHEAD(fd,30); WFIFOW(fd,0) = 0x2b06; memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); WFIFOSET(fd,30); } else { //Reply with nak WFIFOHEAD(fd,30); WFIFOW(fd,0) = 0x2b06; memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); WFIFOL(fd,6) = 0; //Set login1 to 0. WFIFOSET(fd,30); } RFIFOSKIP(fd,39); }
// broadcast sending int mapif_parse_broadcast(int fd) { mapif_broadcast(RFIFOP(fd,16), RFIFOW(fd,2), RFIFOL(fd,4), RFIFOW(fd,8), RFIFOW(fd,10), RFIFOW(fd,12), RFIFOW(fd,14), fd); return 0; }
/*========================================== * *------------------------------------------*/ int chrif_parse(int fd) { int packet_len, cmd; // only process data from the char-server if (fd != char_fd) { ShowDebug("chrif_parse: Disconnecting invalid session #%d (is not the char-server)\n", fd); do_close(fd); return 0; } if (session[fd]->flag.eof) { if (chrif_connected == 1) chrif_disconnect(fd); do_close(fd); return 0; } while (RFIFOREST(fd) >= 2) { cmd = RFIFOW(fd,0); if (cmd < 0x2af8 || cmd >= 0x2af8 + ARRAYLENGTH(packet_len_table) || packet_len_table[cmd-0x2af8] == 0) { int r = intif_parse(fd); // intifに渡す if (r == 1) continue; // intifで処理した if (r == 2) return 0; // intifで処理したが、データが足りない ShowWarning("chrif_parse: session #%d, intif_parse failed (unrecognized command 0x%.4x).\n", fd, cmd); set_eof(fd); return 0; } packet_len = packet_len_table[cmd-0x2af8]; if (packet_len == -1) { // dynamic-length packet, second WORD holds the length if (RFIFOREST(fd) < 4) return 0; packet_len = RFIFOW(fd,2); } if ((int)RFIFOREST(fd) < packet_len) return 0; //ShowDebug("Received packet 0x%4x (%d bytes) from char-server (connection %d)\n", RFIFOW(fd,0), packet_len, fd); switch(cmd) { case 0x2af9: chrif_connectack(fd); break; case 0x2afb: chrif_sendmapack(fd); break; case 0x2afd: chrif_authok(fd); break; case 0x2b00: map_setusers(RFIFOL(fd,2)); chrif_keepalive(fd); break; case 0x2b03: clif_charselectok(RFIFOL(fd,2)); break; case 0x2b04: chrif_recvmap(fd); break; case 0x2b06: chrif_changemapserverack(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOW(fd,18), RFIFOW(fd,20), RFIFOW(fd,22), RFIFOL(fd,24), RFIFOW(fd,28)); break; case 0x2b07: clif_updatemaxid(RFIFOL(fd,2), RFIFOL(fd,6)); break; case 0x2b09: map_addnickdb(RFIFOL(fd,2), (char*)RFIFOP(fd,6)); break; case 0x2b0b: chrif_changedgm(fd); break; case 0x2b0d: chrif_changedsex(fd); break; case 0x2b0f: chrif_char_ask_name_answer(RFIFOL(fd,2), (char*)RFIFOP(fd,6), RFIFOW(fd,30), RFIFOW(fd,32)); break; case 0x2b12: chrif_divorce(RFIFOL(fd,2), RFIFOL(fd,6)); break; case 0x2b13: chrif_accountdeletion(fd); break; case 0x2b14: chrif_accountban(fd); break; case 0x2b15: chrif_recvgmaccounts(fd); break; case 0x2b1b: chrif_recvfamelist(fd); break; case 0x2b1d: chrif_load_scdata(fd); break; case 0x2b1e: chrif_update_ip(fd); break; case 0x2b1f: chrif_disconnectplayer(fd); break; case 0x2b20: chrif_removemap(fd); break; case 0x2b21: chrif_save_ack(fd); break; case 0x2b22: chrif_updatefamelist_ack(fd); break; case 0x2b24: chrif_keepalive_ack(fd); break; default: ShowError("chrif_parse : unknown packet (session #%d): 0x%x. Disconnecting.\n", fd, cmd); set_eof(fd); return 0; } if (fd == char_fd) //There's the slight chance we lost the connection during parse, in which case this would segfault if not checked [Skotlex] RFIFOSKIP(fd, packet_len); } return 0; }
/** * Received a connection request. * @param fd: file descriptor to parse from (client) * @param sd: client session * @param command: packet type sent * @param ip: ipv4 address (client) * S 0064 <version>.L <username>.24B <password>.24B <clienttype>.B * S 0277 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B * S 02b0 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B <g_isGravityID>.B * S 01dd <version>.L <username>.24B <password hash>.16B <clienttype>.B * S 01fa <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.B(index of the connection in the clientinfo file (+10 if the command-line contains "pc")) * S 027c <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.13B(junk) * S 0825 <packetsize>.W <version>.L <clienttype>.B <userid>.24B <password>.27B <mac>.17B <ip>.15B <token>.(packetsize - 0x5C)B * @param fd: fd to parse from (client fd) * @return 0 failure, 1 success */ static int logclif_parse_reqauth(int fd, struct login_session_data *sd, int command, char* ip){ size_t packet_len = RFIFOREST(fd); if( (command == 0x0064 && packet_len < 55) || (command == 0x0277 && packet_len < 84) || (command == 0x02b0 && packet_len < 85) || (command == 0x01dd && packet_len < 47) || (command == 0x01fa && packet_len < 48) || (command == 0x027c && packet_len < 60) || (command == 0x0825 && (packet_len < 4 || packet_len < RFIFOW(fd, 2))) ) return 0; else { int result; char username[NAME_LENGTH]; char password[PASSWD_LENGTH]; unsigned char passhash[16]; uint8 clienttype; bool israwpass = (command==0x0064 || command==0x0277 || command==0x02b0 || command == 0x0825); // Shinryo: For the time being, just use token as password. if(command == 0x0825) { char *accname = RFIFOCP(fd, 9); char *token = RFIFOCP(fd, 0x5C); size_t uAccLen = strlen(accname); size_t uTokenLen = RFIFOREST(fd) - 0x5C; if(uAccLen > NAME_LENGTH - 1 || uAccLen == 0 || uTokenLen > NAME_LENGTH - 1 || uTokenLen == 0) { logclif_auth_failed(sd, 3); return 0; } safestrncpy(username, accname, uAccLen + 1); safestrncpy(password, token, uTokenLen + 1); clienttype = RFIFOB(fd, 8); } else { safestrncpy(username, RFIFOCP(fd,6), NAME_LENGTH); if( israwpass ) { safestrncpy(password, RFIFOCP(fd,30), PASSWD_LENGTH); clienttype = RFIFOB(fd,54); } else { memcpy(passhash, RFIFOP(fd,30), 16); clienttype = RFIFOB(fd,46); } } RFIFOSKIP(fd,RFIFOREST(fd)); // assume no other packet was sent sd->clienttype = clienttype; safestrncpy(sd->userid, username, NAME_LENGTH); if( israwpass ) { ShowStatus("Request for connection of %s (ip: %s)\n", sd->userid, ip); safestrncpy(sd->passwd, password, NAME_LENGTH); if( login_config.use_md5_passwds ) MD5_String(sd->passwd, sd->passwd); sd->passwdenc = 0; } else { ShowStatus("Request for connection (passwdenc mode) of %s (ip: %s)\n", sd->userid, ip); bin2hex(sd->passwd, passhash, 16); // raw binary data here! sd->passwdenc = PASSWORDENC; } if( sd->passwdenc != 0 && login_config.use_md5_passwds ) { logclif_auth_failed(sd, 3); // send "rejected from server" return 0; } result = login_mmo_auth(sd, false); if( result == -1 ) logclif_auth_ok(sd); else logclif_auth_failed(sd, result); } return 1; }
int mapif_parse_SavePet(int fd){ RFIFOHEAD(fd); mapif_save_pet(fd, RFIFOL(fd, 4), (struct s_pet *) RFIFOP(fd, 8)); return 0; }
//character selected, insert into auth db void chrif_authok(int fd) { struct auth_node *node; int account_id = RFIFOL(fd, 4); struct mmo_charstatus *status = (struct mmo_charstatus *)RFIFOP(fd, 20); int char_id = status->char_id; TBL_PC* sd; //Check if both servers agree on the struct's size if( RFIFOW(fd,2) - 20 != sizeof(struct mmo_charstatus) ) { ShowError("chrif_authok: Data size mismatch! %d != %d\n", RFIFOW(fd,2) - 20, sizeof(struct mmo_charstatus)); return; } //Check if we don't already have player data in our server //Causes problems if the currently connected player tries to quit or this data belongs to an already connected player which is trying to re-auth. if ((sd = map_id2sd(account_id)) != NULL) return; if ((node = chrif_search(account_id))) { //Is the character already awaiting authorization? if (node->state != ST_LOGIN) return; //character in logout phase, do not touch that data. if (node->sd) { sd = node->sd; if(node->char_dat == NULL && node->account_id == account_id && node->char_id == char_id && node->login_id1 == RFIFOL(fd, 8)) { //Auth Ok if (pc_authok(sd, RFIFOL(fd, 16), RFIFOL(fd, 12), status)) { chrif_char_online(sd); return; } } else { //Auth Failed pc_authfail(sd); } chrif_char_offline(sd); //Set client offline chrif_auth_delete(account_id, char_id, ST_LOGIN); return; } //When we receive double login info and the client has not connected yet, //discard the older one and keep the new one. chrif_auth_delete(node->account_id, node->char_id, ST_LOGIN); } // Awaiting for client to connect. node = ers_alloc(auth_db_ers, struct auth_node); memset(node, 0, sizeof(struct auth_node)); node->char_dat = (struct mmo_charstatus *) aMalloc(sizeof(struct mmo_charstatus)); node->account_id=account_id; node->char_id=char_id; node->login_id1=RFIFOL(fd, 8); node->connect_until_time=RFIFOL(fd, 12); node->login_id2=RFIFOL(fd, 16); memcpy(node->char_dat,status,sizeof(struct mmo_charstatus)); node->node_created=gettick(); idb_put(auth_db, account_id, node); }