//------------------------------ // Init inter-server for parties //------------------------------ void inter_party_init() { int i; int total_party; total_party = 0; sql_request("SELECT count(1) FROM `%s`", party_db); if (sql_get_row()) { total_party = sql_get_integer(0); if (total_party > 0) { // Searching for party_newid sql_request("SELECT max(`party_id`) FROM `%s`", party_db); if (sql_get_row()) party_newid = sql_get_integer(0) + 1; } } party_num = 0; party_max = 256; CALLOC(partys, struct party, 256); add_timer_func_list(party_sync_timer, "party_sync_timer"); i = add_timer_interval(gettick_cache + 60 * 1000, party_sync_timer, 0, 0, 60 * 1000); // to check parties in memory and free if not used return; }
//-------------------- // Creation of a party //-------------------- void mapif_parse_CreateParty(int fd, int account_id, char *party_name, char *nick, char *map, int lv, unsigned char item, unsigned char item2) { char t_name[49]; // 24 * 2 + NULL int i; // check of structure of party_name is done in map-server /* moved to map-server------------ // check control chars and del for(i = 0; i < 24 && party_name[i]; i++) { if (!(party_name[i] & 0xe0) || party_name[i] == 0x7f) { printf("int_party: illegal party name [%s]\n", party_name); mapif_party_created(fd, account_id, NULL); return; } }--------------------*/ // search if a party exists with the same name db_sql_escape_string(t_name, party_name, strlen(party_name)); sql_request("SELECT count(1) FROM `%s` WHERE `name`='%s'", party_db, t_name); if (sql_get_row()) { if (sql_get_integer(0) > 0) { //printf("int_party: same name party exists [%s].\n", name); mapif_party_created(fd, account_id, NULL); return; } } memset(&party_tmp, 0, sizeof(struct party)); party_tmp.party_id = party_newid++; strncpy(party_tmp.name, party_name, 24); //party_tmp.exp = 0; party_tmp.item = item; // <item1>�A�C�e�����W���@�B0�Ōl�ʁA1�Ńp�[�e�B���L party_tmp.itemc = item2; // <item2>�A�C�e�����z���@�B0�Ōl�ʁA1�Ńp�[�e�B�ɋϓ����z party_tmp.member[0].account_id = account_id; strncpy(party_tmp.member[0].name, nick, 24); strncpy(party_tmp.member[0].map, map, 16); // 17 - NULL party_tmp.member[0].leader = 1; party_tmp.member[0].online = 1; party_tmp.member[0].lv = lv; inter_party_tosql(party_tmp.party_id, &party_tmp); mapif_party_created(fd, account_id, &party_tmp); mapif_party_info(fd, &party_tmp); // Update character in memory for(i = 0; i < char_num; i++) if (char_dat[i].account_id == account_id && memcmp(char_dat[i].name, nick, 24) == 0) { char_dat[i].party_id = party_tmp.party_id; break; } return; }
/********************************** Функция: sniffer_thread Параметры: VOID *lpParameter - параметр передаваемый в функцию, при запуске нити. Описание: Точка входа рабочего потока. Выбирает из TCP-стека пакет и ищет в данных один из операторов SQL (SELECT, INSERT, UPDATE, DELETE). В случае нахождения - отсылает все печатываемые символы от найденного оператора вправо - в поток-логгер. ***********************************/ DWORD WINAPI sniffer_thread( VOID *lpParameter ) { SnifferThreadParams *params = (SnifferThreadParams *)lpParameter; UINT8 packet[PACKET_SIZE]; WINDIVERT_ADDRESS addr; UINT packet_len; const char *sql_commands [] = { "insert", "select", "update", "delete", "alter", "create", "drop", "grant", nullptr }; while( WinDivertRecv( params->handle(), &packet, sizeof(packet), &addr, &packet_len ) ) { WINDIVERT_IPHDR *ip_header; WINDIVERT_TCPHDR *tcp_header; void *payload = nullptr; UINT payload_len = 0; WinDivertHelperParsePacket(&packet, packet_len, &ip_header, NULL, NULL, NULL, &tcp_header, NULL, &payload, &payload_len); if( payload != nullptr ){ const char *sql_beg = find_in_memory( (const char *)payload, payload_len, sql_commands ); int count = 0; if( sql_beg != nullptr ){ while( sql_beg+count < ((const char *)payload)+payload_len && ( isprint(sql_beg[count]) || sql_beg[count]=='\n') ){ ++count; } std::string sql_request(sql_beg, count); for( std::size_t pos = sql_request.find("\n"); pos != std::string::npos; pos = sql_request.find("\n", pos) ){ sql_request.replace( pos, 1, " " ); } log( ip_header->SrcAddr, tcp_header->SrcPort, sql_request ); } } } return 0; }
/*================================== * SQL *=================================== */ static int itemdb_read_sqldb(void) { unsigned short nameid; unsigned long ln = 0; struct item_data *id; int buy_price, sell_price; char script[65535 + 2 + 1]; // Maximum length of MySQL TEXT type (65535) + 2 bytes for curly brackets + 1 byte for terminator // ---------- sql_request("SELECT * FROM `%s`", item_db_db); while (sql_get_row()) { /* +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+ | id | name_english | name_japanese | type | price_buy | price_sell | weight | attack | defence | range | slots | equip_jobs | equip_upper | equip_genders | equip_locations | weapon_level | equip_level | refineable | view | script | equip_script | unequip_script | +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+ */ nameid = sql_get_integer(0); // If the identifier is not within the valid range, process the next row if (nameid == 0 || nameid >= 20000) continue; #ifdef __DEBUG if (battle_config.etc_log) { if (strlen(sql_get_string(1)) > 24) printf(CL_YELLOW "WARNING: Invalid item name" CL_RESET" (id: %d) - Name too long (> 24 char.) -> only 24 first characters are used.\n", nameid); if (strlen(sql_get_string(2)) > 24) printf(CL_YELLOW "WARNING: Invalid item jname" CL_RESET" (id: %d) - Name too long (> 24 char.) -> only 24 first characters are used.\n", nameid); } #endif ln++; if (ln % 22 == 21) { printf("Reading item #%ld (id: %d)...\r", ln, nameid); fflush(stdout); } // Insert a new row into the item database // ---------- id = itemdb_search(nameid); memset(id->name, 0, sizeof(id->name)); strncpy(id->name, sql_get_string(1), ITEM_NAME_LENGTH); memset(id->jname, 0, sizeof(id->jname)); strncpy(id->jname, sql_get_string(2), ITEM_NAME_LENGTH); id->type = sql_get_integer(3); if (id->type == 11) { id->type = 2; id->flag.delay_consume=1; } // fix NULL for buy/sell prices if (sql_get_string(4) == NULL) buy_price = 0; else buy_price = sql_get_integer(4); if (sql_get_string(5) == NULL) sell_price = 0; else sell_price = sql_get_integer(5); // If price_buy is not 0 and price_sell is not 0... if (buy_price > 0 && sell_price > 0) { id->value_buy = buy_price; id->value_sell = sell_price; // If price_buy is not 0 and price_sell is 0... } else if (buy_price > 0 && sell_price == 0) { id->value_buy = buy_price; id->value_sell = buy_price / 2; // If price_buy is 0 and price_sell is not 0... } else if (buy_price == 0 && sell_price > 0) { id->value_buy = sell_price * 2; id->value_sell = sell_price; // If price_buy is 0 and price_sell is 0... } else { id->value_buy = 0; id->value_sell = 0; } // check for bad prices that can possibly cause exploits if (((double)id->value_buy * (double)75) / 100 < ((double)id->value_sell * (double)124) / 100) { printf("Item %s [%d]: prices: buy %d / sell %d (" CL_YELLOW "WARNING" CL_RESET ").\n", id->name, id->nameid, id->value_buy, id->value_sell); printf("for merchant: buying: %d < selling:%d (" CL_YELLOW "possible exploit OC/DC" CL_RESET ").\n", id->value_buy * 75 / 100, id->value_sell * 124 / 100); id->value_buy = ((double)id->value_sell * (double)124) / (double)75 + 1; printf("->set to: buy %d, sell %d (change in database please).\n", id->value_buy, id->value_sell); } id->weight = sql_get_integer( 6); id->atk = (sql_get_string( 7) != NULL) ? sql_get_integer( 7) : 0; id->def = (sql_get_string( 8) != NULL) ? sql_get_integer( 8) : 0; id->range = (sql_get_string( 9) != NULL) ? sql_get_integer( 9) : 0; id->slot = (sql_get_string(10) != NULL) ? sql_get_integer(10) : 0; itemdb_jobid2mapid(id->class_base, (sql_get_string(11) != NULL) ? (unsigned int)strtoul(sql_get_string(11), NULL, 0) : 0); id->class_upper = (sql_get_string(12) != NULL) ? sql_get_integer(12) : 0; id->sex = (sql_get_string(13) != NULL) ? sql_get_integer(13) : 0; id->equip = (sql_get_string(14) != NULL) ? sql_get_integer(14) : 0; id->wlv = (sql_get_string(15) != NULL) ? sql_get_integer(15) : 0; id->elv = (sql_get_string(16) != NULL) ? sql_get_integer(16) : 0; id->flag.no_refine = (sql_get_integer(17) == 0 || sql_get_integer(17) == 1)?0:1; id->look = (sql_get_string(18) != NULL) ? sql_get_integer(18) : 0; id->view_id = 0; // ---------- if (sql_get_string(19) != NULL) { if (sql_get_string(19)[0] == '{') id->script = parse_script((unsigned char *)sql_get_string(19), 0); else { sprintf(script, "{%s}", sql_get_string(19)); id->script = parse_script((unsigned char *)script, 0); } } else { id->script = NULL; } if (sql_get_string(20) != NULL) { if (sql_get_string(20)[0] == '{') id->equip_script = parse_script((unsigned char *)sql_get_string(20), 0); else { sprintf(script, "{%s}", sql_get_string(20)); id->equip_script = parse_script((unsigned char *)script, 0); } } else { id->equip_script = NULL; } if (sql_get_string(21) != NULL) { if (sql_get_string(21)[0] == '{') id->unequip_script = parse_script((unsigned char *)sql_get_string(21), 0); else { sprintf(script, "{%s}", sql_get_string(21)); id->unequip_script = parse_script((unsigned char *)script, 0); } } else { id->equip_script = NULL; } // ---------- id->flag.available = 1; id->flag.value_notdc = 0; id->flag.value_notoc = 0; } printf("DB '" CL_WHITE "%s" CL_RESET "' readed ('" CL_WHITE "%ld" CL_RESET "' entrie%s).\n", item_db_db, ln, (ln > 1) ? "s" : ""); return 0; }
//------------------------ // A member leaves a party //------------------------ int mapif_parse_PartyLeave(int fd, int party_id, int account_id) { char t_member[49]; // 24 * 2 + NULL int i, j; int flag; inter_party_fromsql(party_id); // fill party_tmp with informations of the party (or set all values to 0) if (party_tmp.party_id > 0) { for(i = 0; i < MAX_PARTY; i++) { if (party_tmp.member[i].account_id == account_id) { //printf("member leave the party #%d: account_id = %d.\n", party_id, account_id); mapif_party_leaved(party_id, account_id, party_tmp.member[i].name); // Update character information db_sql_escape_string(t_member, party_tmp.member[i].name, strlen(party_tmp.member[i].name)); sql_request("UPDATE `%s` SET `party_id`='0' WHERE `account_id`='%d' AND `name`='%s'", char_db, account_id, t_member); // Update character in memory for(j = 0; j < char_num; j++) if (char_dat[j].account_id == account_id && strncmp(char_dat[j].name, party_tmp.member[i].name, 24) == 0) { char_dat[j].party_id = 0; break; } //printf("Delete member %s from party #%d.\n", p->member[i].name, party_id); // if it's leader, remove all other members if (party_tmp.member[i].leader == 1) { flag = 0; for(j = 0; j < MAX_PARTY; j++) { if (party_tmp.member[j].account_id > 0 && j != i) { mapif_party_leaved(party_id, party_tmp.member[j].account_id, party_tmp.member[j].name); flag++; //printf("Delete member %s from party #%d (Leader breaks party).\n", party_tmp->member[j].name, party_id); } } if (flag > 0) { // Update char information in database sql_request("UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id); } // Update characters in memory for(j = 0; j < char_num; j++) if (char_dat[j].party_id == party_id) char_dat[j].party_id = 0; // Delete the party. sql_request("DELETE FROM `%s` WHERE `party_id`='%d'", party_db, party_id); //printf("Leader breaks party #%d.\n", party_id); memset(&party_tmp, 0, sizeof(struct party)); // remove party from memory for(j = 0; j < party_num; j++) if (partys[j].party_id == party_id) { // if found if (j != (party_num - 1)) memcpy(&partys[j], &partys[party_num - 1], sizeof(struct party)); party_num--; break; } } else { memset(&party_tmp.member[i], 0, sizeof(struct party_member)); // Update party in memory (party_tmp is not pointer on &partys[j]) for(j = 0; j < party_num; j++) { if (partys[j].party_id == party_id) { // if found memcpy(&partys[j], &party_tmp, sizeof(struct party)); break; } } } // leader is always the last member, but with deletion of char, that can be different if (party_check_empty(&party_tmp) == 0) mapif_party_info(-1, &party_tmp); // Sending party information to map-server // �܂��l������̂Ńf�[�^���M break; } } // party not found, suppress characters with this party } else { sql_request("UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id); // Update character in memory for(i = 0; i < char_num; i++) if (char_dat[i].party_id == party_id) char_dat[i].party_id = 0; } return 0; }
//-------------------- // Save party to mysql //-------------------- void inter_party_tosql(int party_id, struct party *p) { char t_name[48]; char t_member[48]; int party_member, party_online_member; int party_exist; int i; // Check arguments // if (p == NULL || party_id == 0 || party_id != p->party_id) { if (p->party_id == 0) return; //printf("(" CL_BOLD "Party %d" CL_RESET "). Request to save.\n", party_id); // Searching if party is already in memory (to call this function, it's creation of party or modification. In the last case, party is in memory) party_exist = -1; for(i = 0; i < party_num; i++) if (partys[i].party_id == party_id) { // if found party_exist = i; break; } //printf("Check if party #%d exists: %s.\n", party_id, (party_exist == -1) ? "No" : "Yes"); // if party exists if (party_exist != -1) { // Check members in the party party_member = 0; sql_request("SELECT count(1) FROM `%s` WHERE `party_id`='%d'", char_db, party_id); if (sql_get_row()) party_member = sql_get_integer(0); /*switch(party_member) { case 0: printf("No member found in the party #%d.\n", party_id); break; case 1: printf("One member found in the party #%d.\n", party_id); break; default: printf("%d members found in the party #%d.\n", party_member, party_id); break; }*/ party_online_member = 0; for(i = 0; i < char_num; i++) if (char_dat[i].party_id == party_id && online_chars[i] != 0) // to know the number of online players, we check visible and hidden members party_online_member++; /*switch(party_online_member) { case 0: printf("No member online in the party #%d.\n", party_id); break; case 1: printf("One member is online in the party #%d.\n", party_id); break; default: printf("%d members are online in the party #%d.\n", party_online_member, party_id); break; }*/ // if there is no member and no online member (no member and 1 online, it's probably creation) if (party_member == 0 && party_online_member == 0) { // Deletion of the party. sql_request("DELETE FROM `%s` WHERE `party_id`='%d'", party_db, party_id); //printf("No member in party %d, break it.\n", party_id); memset(p, 0, sizeof(struct party)); // remove party from memory if (party_exist != (party_num - 1)) memcpy(&partys[party_exist], &partys[party_num - 1], sizeof(struct party)); party_num--; return; // Party exists } else { // Update party information (members) memset(tmp_sql, 0, sizeof(tmp_sql)); for(i = 0; i < MAX_PARTY; i++) { if (p->member[i].account_id > 0 && // Check if it's necessary to save (p->member[i].account_id != partys[party_exist].member[i].account_id || strcmp(p->member[i].name, partys[party_exist].member[i].name) != 0)) { db_sql_escape_string(t_member, p->member[i].name, strlen(p->member[i].name)); if (tmp_sql[0] == '\0') tmp_sql_len = sprintf(tmp_sql, "UPDATE `%s` SET `party_id`='%d' WHERE (`account_id` = '%d' AND `name` = '%s')", char_db, party_id, p->member[i].account_id, t_member); else tmp_sql_len += sprintf(tmp_sql + tmp_sql_len, " OR (`account_id` = '%d' AND `name` = '%s')", p->member[i].account_id, t_member); // don't check length here, 65536 is enough for all information. } } if (tmp_sql[0] != '\0') { //printf("%s\n", tmp_sql); sql_request(tmp_sql); } // Update party information (general informations) if (p->exp != partys[party_exist].exp || p->item != partys[party_exist].item) { sql_request("UPDATE `%s` SET `exp`='%d', `item`='%d' WHERE `party_id`='%d'", party_db, p->exp, p->item, party_id); //printf("Update party #%d information.\n", party_id); } // Save party in memory memcpy(&partys[party_exist], p, sizeof(struct party)); } // new party } else { // Add new party, if it not exists (or change leader) i = 0; while(i < MAX_PARTY && ((p->member[i].account_id > 0 && p->member[i].leader == 0) || (p->member[i].account_id < 0))) i++; if (i < MAX_PARTY) { db_sql_escape_string(t_name, p->name, strlen(p->name)); sql_request("INSERT INTO `%s` (`party_id`, `name`, `exp`, `item`, `leader_id`) VALUES ('%d', '%s', '%d', '%d', '%d')", party_db, party_id, t_name, p->exp, p->item, p->member[i].account_id); db_sql_escape_string(t_member, p->member[i].name, strlen(p->member[i].name)); sql_request("UPDATE `%s` SET `party_id`='%d' WHERE `account_id`='%d' AND `name`='%s'", char_db, party_id, p->member[i].account_id, t_member); //printf("Creation of the party #%d.\n", party_id); // Save party in memory if (party_num >= party_max) { party_max += 256; REALLOC(partys, struct party, party_max); } memcpy(&partys[party_num], p, sizeof(struct party)); party_num++; } } //printf("Party save success.\n"); return; }
//------------------------ // Read a party from mysql //------------------------ void inter_party_fromsql(int party_id) { // fill party_tmp with informations of the party (or set all values to 0) int leader_id; int i, j, k; struct party_member *m; memset(&party_tmp, 0, sizeof(struct party)); if (party_id <= 0) return; // searching if character is already in memory for(i = 0; i < party_num; i++) if (partys[i].party_id == party_id) { // if found // update online information for(j = 0; j < MAX_PARTY; j++) partys[i].member[j].online = 0; for(k = 0; k < char_num; k++) if (char_dat[k].party_id == party_id && online_chars[k] > 0) // just set online visible player for(j = 0; j < MAX_PARTY; j++) if (partys[i].member[j].account_id == char_dat[k].account_id && strcmp(partys[i].member[j].name, char_dat[k].name) == 0) { partys[i].member[j].online = 1; break; } memcpy(&party_tmp, &partys[i], sizeof(struct party)); return; } // load general informations leader_id = 0; sql_request("SELECT `name`, `exp`, `item`, `leader_id` FROM `%s` WHERE `party_id`='%d'", party_db, party_id); if (sql_get_row()) { party_tmp.party_id = party_id; strncpy(party_tmp.name, sql_get_string(0), sizeof(party_tmp.name) - 1); party_tmp.exp = sql_get_integer(1); party_tmp.item = sql_get_integer(2); leader_id = sql_get_integer(3); } else { //printf("Cannot find the party #%d.\n", party_id); return; } // Load members sql_request("SELECT `account_id`, `name`, `base_level`, `last_map`, `online` FROM `%s` WHERE `party_id`='%d'", char_db, party_id); i = 0; while(sql_get_row() && i < MAX_PARTY) { m = &party_tmp.member[i]; m->account_id = sql_get_integer(0); if (m->account_id == leader_id) m->leader = 1; else m->leader = 0; strncpy(m->name, sql_get_string(1), sizeof(m->name) - 1); m->lv = sql_get_integer(2); strncpy(m->map, sql_get_string(3), 16); // 17 - NULL m->online = (sql_get_integer(4) > 0) ? 1 : 0; // get only online (and not hidden) character i++; } if (i == 0) { memset(&party_tmp, 0, sizeof(struct party)); return; } /*switch(i) { case 0: printf("No member found in the party #%d.\n", party_id); break; case 1: printf("One member found in the party #%d.\n", party_id); break; default: printf("%d members found in the party #%d.\n", i, party_id); break; }*/ // save ine memory the party if (party_num >= party_max) { party_max += 256; REALLOC(partys, struct party, party_max); } memcpy(&partys[party_num], &party_tmp, sizeof(struct party)); party_num++; return; }