#define MODULE_LOG_PREFIX "gbox/remm" #include "globals.h" #ifdef MODULE_GBOX #include "module-gbox-remm.h" #include "module-gbox.h" #include "module-gbox-helper.h" #include "oscam-string.h" #include "oscam-client.h" #include "oscam-lock.h" #include "oscam-time.h" #include "oscam-reader.h" #include "oscam-files.h" #include "module-dvbapi.h" #include "oscam-emm.h" static void gbox_send_remm_ack_msg(struct s_client *cli, uint16_t caid, uint32_t provider, uint8_t dvbapi_stat, uint8_t ack) { uint8_t outbuf[32]; struct gbox_peer *peer = cli->gbox; uint16_t local_gbox_id = gbox_get_local_gbox_id(); uint32_t local_gbox_pw = gbox_get_local_gbox_password(); gbox_message_header(outbuf, MSG_REM_EMM, peer->gbox.password, local_gbox_pw); outbuf[10] = MSGID_REMM_ACK; i2b_buf(2, peer->gbox.id, outbuf +11); i2b_buf(2, local_gbox_id, outbuf + 13); outbuf[15] = ack; outbuf[16] = dvbapi_stat; i2b_buf(2, caid, outbuf +17); i2b_buf(4, provider, outbuf +19); outbuf[23] = 0; outbuf[24] = 0; outbuf[25] = 0; outbuf[26] = 0; gbox_send(cli, outbuf, 27); if (ack == PEER_AU_BLOCKED) { cs_log("<- send REJECT REMM msg to peer %04X for caid: %04X", peer->gbox.id, caid); } if (ack == PEER_AU_READY) { cs_log("<- send ACCEPT REMM msg to peer %04X for caid: %04X", peer->gbox.id, caid); } if (ack == PEER_AU_UNREADY) { cs_log("<- send WARNING to peer %04X: my dvbapi unready for AU caid: %04X", peer->gbox.id, caid); } return; } static void gbox_recvd_remm_ack_msg(struct s_client *cli, uint8_t *buf, int32_t n) { if (!cli || !cli->gbox || !buf || n != 27) { return; } struct gbox_peer *peer; peer = cli->gbox; uint8_t ack = buf[15]; uint8_t dvbapi_stat = buf[16]; uint16_t rpeer = b2i(2, buf +11); uint16_t rcaid = b2i(2, buf +17); //uint32_t rprovid = b2i(4, buf +19); if (ack == PEER_AU_BLOCKED) { cs_log("-> Peer %04X %s rejected REMM for caid %04X - requesting peer %04X blocked", peer->gbox.id, cli->reader->label, rcaid, rpeer ); } if (ack == PEER_AU_READY) { cs_log("-> MSG from peer %04X %s: Accept REMM REQ for caid %04X", peer->gbox.id, cli->reader->label, rcaid); } if (ack == PEER_AU_UNREADY) { cs_log("-> WARNING: Peer %04X %s dvbapi AU unready for caid %04X", peer->gbox.id, cli->reader->label, rcaid); cs_log_dbg(D_EMM,"Peer %04X dvbapi AU status: dvbapi_au: %1d - dvbapi_usr_autoau: %1d - dvbapi_usr_aulist: %1d", peer->gbox.id, (dvbapi_stat & 1) ? 1 : 0, (dvbapi_stat & 2) ? 1 : 0, (dvbapi_stat & 4) ? 1 : 0 ); } } static uint8_t check_dvbapi_au_ready( void) { #ifdef HAVE_DVBAPI uint8_t dvbapi_stat = 0; if (module_dvbapi_enabled()) { if(cfg.dvbapi_au) { dvbapi_stat |= 1; } struct s_client *cl; cs_readlock(__func__, &clientlist_lock); for(cl = first_client; cl; cl = cl->next) { if(cl->typ == 'c' && cl->account && is_dvbapi_usr(cl->account->usr)) { if(cl->account->autoau) { dvbapi_stat |= 2; break; } if(ll_count(cl->account->aureader_list)) { dvbapi_stat |= 4; break; } } } cs_readunlock(__func__, &clientlist_lock); } return dvbapi_stat; #else return 0; #endif } uint8_t check_valid_remm_peer(uint16_t peer_id) { if (cfg.accept_remm_peer_num > 0) { int i; for (i = 0; i < cfg.accept_remm_peer_num; i++) { if (cfg.accept_remm_peer[i] == peer_id) { return 1; } } } return 0; } static void gbox_recvd_remm_req(struct s_client *cli, uint8_t *buf, int32_t n) { if (!cli || !cli->gbox || !buf || !cli->reader || n != 122) { return; } struct gbox_peer *peer; peer = cli->gbox; uint16_t rcaid = b2i(2, buf +23); uint32_t rprovid = b2i(4, buf +17); //uint16_t tcli_peer = b2i(2, buf +11); //uint16_t tsrv_peer = b2i(2, buf +13); uint8_t dvbapi_stat = check_dvbapi_au_ready(); if (!check_valid_remm_peer( peer->gbox.id)) { gbox_send_remm_ack_msg(cli, rcaid, rprovid, dvbapi_stat, PEER_AU_BLOCKED); handle_attack(cli, GBOX_ATTACK_REMM_REQ_BLOCKED, peer->gbox.id); cs_log("Reject REMM REQ for caid %04X) - peer %04X blocked for AU", rcaid, peer->gbox.id); return; } //if (tcli_peer != local_gbox.id) // { forward remm req to target client peer} struct s_reader *rdr = cli->reader; rdr->gbox_remm_peer = peer->gbox.id; rdr->last_g = time(NULL); // last receive is now rdr->auprovid = rprovid; rdr->caid = rcaid; memcpy(rdr->hexserial, buf + 29, 6); rdr->hexserial[6] = 0; rdr->hexserial[7] = 0; rdr->nprov = buf[37]; int32_t i; for(i = 0; i < rdr->nprov; i++) { if(caid_is_betacrypt(rdr->caid) || caid_is_irdeto(rdr->caid)) { rdr->prid[i][0] = buf[38 + (i * 5)]; memcpy(&rdr->prid[i][1], &buf[40 + (i * 5)], 3); } else { rdr->prid[i][2] = buf[38 + (i * 5)]; rdr->prid[i][3] = buf[39 + (i * 5)]; memcpy(&rdr->sa[i][0], &buf[40 + (i * 5)], 4); } } rdr->blockemm = 0; rdr->blockemm |= (buf[117] == 1) ? 0 : 0x80; // remm marker bit rdr->blockemm |= (buf[118] == 1) ? 0 : EMM_GLOBAL; rdr->blockemm |= (buf[119] == 1) ? 0 : EMM_SHARED; rdr->blockemm |= (buf[120] == 1) ? 0 : EMM_UNIQUE; rdr->blockemm |= (buf[121] == 1) ? 0 : EMM_UNKNOWN; cs_log("-> received REMM REQ for type %s%s%s%s caid %04X from peer %04X:%s", buf[120]==1 ? "UQ ":"", buf[119]==1 ? "SH ":"", buf[118]==1 ? "GL ":"", buf[121]==1 ? "UK":"", rdr->caid, peer->gbox.id, rdr->label); if (dvbapi_stat == 3 || dvbapi_stat == 5) { gbox_send_remm_ack_msg(cli, rdr->caid, rdr->auprovid, dvbapi_stat, PEER_AU_READY); cs_log_dbg(D_EMM,"my dvbapi ready for AU: dvbapi_au: %1d - dvbapi_usr_autoau: %1d - dvbapi_usr_aulist: %1d", (dvbapi_stat & 1) ? 1 : 0, (dvbapi_stat & 2) ? 1 : 0, (dvbapi_stat & 4) ? 1 : 0 ); } else { gbox_send_remm_ack_msg(cli, rdr->caid, rdr->auprovid, dvbapi_stat, PEER_AU_UNREADY); cs_log_dbg(D_EMM,"dvbapi status: dvbapi_au: %1d - dvbapi_usr_autoau: %1d - dvbapi_usr_aulist: %1d", (dvbapi_stat & 1) ? 1 : 0, (dvbapi_stat & 2) ? 1 : 0, (dvbapi_stat & 4) ? 1 : 0 ); } write_msg_info(cli, MSGID_REMM, 0, 1); } static void gbox_recvd_remm_data(struct s_client *cli, uint8_t *buf, int32_t buflen, int32_t emmlen) { if(!cli || !cli->gbox || !buf || buflen < 30 || emmlen +27 > buflen || emmlen < 3 || emmlen + 27 > MAX_EMM_SIZE) { return; } struct gbox_peer *peer; peer = cli->gbox; uint16_t rcaid = b2i(2, buf + 15); uint32_t recvd_remm_crc = b2i(4, buf + 23); uint32_t calc_remm_crc = gbox_get_checksum(&buf[0] +27, emmlen); cs_log_dbg(D_EMM,"received remm from peer: %04X caid: %04X (remm_crc = %08X - calc_remm_crc = %08X)", peer->gbox.id, rcaid, recvd_remm_crc, calc_remm_crc); if(recvd_remm_crc == calc_remm_crc) { EMM_PACKET remm; memset(&remm, 0, sizeof(remm)); remm.emmlen = emmlen; memcpy(remm.caid, buf +15, 2); memcpy(remm.provid, buf +17 , 4); memcpy(remm.emm, buf +27, remm.emmlen); do_emm(cur_client(), &remm); } else { cs_log_dbg(D_EMM,"reject received REMM from peer %04X caid: %04X - crc failed - %08X != %08X", peer->gbox.id, rcaid, recvd_remm_crc, calc_remm_crc); } return; } void gbox_recvd_remm_cmd_switch(struct s_client *cli, uint8_t *buf, int32_t n) { if (!cli || !cli->gbox || !buf || n < 26) { return; } struct gbox_peer *peer; peer = cli->gbox; uint8_t cmd_id = buf[10]; switch(cmd_id) { case MSGID_REMM_REQ: cs_log_dbg(D_EMM,"-> Incoming REMM request (%d bytes) from %04X %s - %s", n, peer->gbox.id, username(cli), cli->reader->device); gbox_recvd_remm_req(cli, buf, n); break; case MSGID_REMM_DATA: cs_log_dbg(D_EMM,"-> Incoming gbox remote EMM data (%d bytes total - %d bytes emm-len) from %04X %s - %s", n, buf[21], peer->gbox.id, username(cli), cli->reader->device); gbox_recvd_remm_data(cli, buf, n, buf[21]); // buf[21]) = emm length break; case MSGID_REMM_ACK: cs_log_dbg(D_EMM,"-> Incoming REMM ACK (%d bytes) from %04X %s - %s", n, peer->gbox.id, username(cli), cli->reader->device); gbox_recvd_remm_ack_msg(cli, buf, n); break; default: cs_log("received unknown remm cmd_id: %d %d bytes from %04X %s - %s", cmd_id, n, peer->gbox.id, username(cli), cli->reader->device); return; } } void gbox_send_remm_req(struct s_client *cli, ECM_REQUEST *er) { if (!cli || !cli->gbox || !er) { return; } int32_t i; uint8_t mbuf[1024]; struct s_client *cl = cur_client(); struct gbox_peer *peer = cli->gbox; struct s_reader *aureader = NULL, *rdr = NULL; if(er->selected_reader && !er->selected_reader->audisabled && ll_contains(cl->aureader_list, er->selected_reader)) { aureader = er->selected_reader; } if(!aureader && cl->aureader_list) { LL_ITER itr = ll_iter_create(cl->aureader_list); while((rdr = ll_iter_next(&itr))) { if(emm_reader_match(rdr, er->caid, er->prid)) { aureader = rdr; break; } } } if(!aureader) { return; } uint16_t au_caid = aureader->caid; if(!au_caid && caid_is_bulcrypt(er->caid)) // Bulcrypt has 2 caids and aureader->caid can't be used. Use ECM_REQUEST caid for AU. { au_caid = er->caid; } if(cl->lastcaid != er->caid) { cl->disable_counter = 0; } cl->lastcaid = er->caid; cl->disable_counter++; if (!cli->reader->gbox_force_remm && cl->disable_counter < 6) // delay 6 ecm { return; } if(!memcmp(cl->lastserial, aureader->hexserial, 8)) { cl->disable_counter = 0; return; } memcpy(cl->lastserial, aureader->hexserial, 8); if(au_caid) { cl->disable_counter = 0; } else { return; } uint8_t total_ent = 0; uint8_t active_ent = 0; if(aureader->ll_entitlements) // check for active entitlements { time_t now = time((time_t *)0); LL_ITER itr = ll_iter_create(aureader->ll_entitlements); S_ENTITLEMENT *ent; while((ent = ll_iter_next(&itr))) { total_ent++; if((ent->end > now) && (ent->type != 7)) { active_ent++; } } //cs_log("AU card %s: Total entitlements: %d - active entitlements: %d", aureader->label, total_ent, active_ent); } if(total_ent && cli->reader->gbox_force_remm) { if(active_ent >= cli->reader->gbox_force_remm) { cs_log("WARNING: Card '%s' got %d active entitlements - consider to disable 'force_remm'", aureader->label, active_ent); } } memset(mbuf, 0, sizeof(mbuf)); uint16_t local_gbox_id = gbox_get_local_gbox_id(); uint32_t local_gbox_pw = gbox_get_local_gbox_password(); gbox_message_header(mbuf, MSG_REM_EMM, peer->gbox.password, local_gbox_pw); mbuf[10] = MSGID_REMM_REQ; i2b_buf(2, peer->gbox.id, mbuf + 11); i2b_buf(2, local_gbox_id, mbuf + 13); i2b_buf(2, er->srvid, mbuf + 15); // override emm provid with auprovid if set in server reader config if(aureader->auprovid) { if(aureader->auprovid != er->prid) { i2b_buf(4, aureader->auprovid, mbuf +17); } else { i2b_buf(4, er->prid, mbuf +17); } } else { i2b_buf(4, er->prid, mbuf +17); } i2b_buf(2, er->pid, mbuf +21); i2b_buf(2, au_caid, mbuf +23); memcpy(mbuf +29, aureader->hexserial, 6); // serial 6 bytes mbuf[37] = aureader->nprov; for(i = 0; i < aureader->nprov; i++) { if(caid_is_betacrypt(au_caid) || caid_is_irdeto(au_caid)) { mbuf[38 + (i * 5)] = aureader->prid[i][0]; memcpy(&mbuf[40 + (i * 5)], &aureader->prid[i][1], 3); } else { mbuf[38 + (i * 5)] = aureader->prid[i][2]; mbuf[39 + (i * 5)] = aureader->prid[i][3]; memcpy(&mbuf[40 + (i * 5)], &aureader->sa[i][0], 4); // for conax we need at least 4 Bytes } if(i >= 15) { break; } } mbuf[117] = aureader->blockemm | 0x80; // set remm marker bit if(au_caid == 0x0D96 || au_caid == 0x0D98 ) // these caids needs globals { mbuf[118] = (aureader->blockemm & EMM_GLOBAL && !(aureader->saveemm & EMM_GLOBAL)) ? 0 : 1; } else { mbuf[118] = 0; } mbuf[119] = (aureader->blockemm & EMM_SHARED && !(aureader->saveemm & EMM_SHARED)) ? 0 : 1; mbuf[120] = (aureader->blockemm & EMM_UNIQUE && !(aureader->saveemm & EMM_UNIQUE)) ? 0 : 1; mbuf[121] = (aureader->blockemm & EMM_UNKNOWN && !(aureader->saveemm & EMM_UNKNOWN)) ? 0 : 1; cs_log("<- %04X sends REMM REQ for type = %s%s%s%s to %s peer-id=%04X for reader=%s, caid=%04X", local_gbox_id, mbuf[120] == 1 ? "UQ " : "", mbuf[119] == 1 ? "SH " : "", mbuf[118] == 1 ? "GL " : "", mbuf[121] == 1 ? "UK" : "", username(cur_client()), peer->gbox.id, aureader->label, au_caid ); cs_log_dump_dbg(D_EMM, mbuf, 122, "<- send remm request, (data_len=%d):", 122); gbox_send(cli, mbuf, 122); return; } int32_t gbox_send_remm_data(EMM_PACKET *ep) { struct s_client *cli = cur_client(); struct gbox_peer *peer = cli->gbox; if(!cli->gbox || !cli->reader->tcp_connected || !ep || !cli->reader->gbox_remm_peer) { return 0; } uint32_t remm_crc = gbox_get_checksum(&ep->emm[0], ep->emmlen); if(remm_crc == peer->last_remm_crc) { return 0; } peer->last_remm_crc = remm_crc; uint8_t *buf; if(!cs_malloc(&buf, ep->emmlen +27 +15)) { return -1; } memset(buf, 0, 26); memset(buf +27, 0xff, ep->emmlen + 15); uint16_t local_gbox_id = gbox_get_local_gbox_id(); uint32_t local_gbox_pw = gbox_get_local_gbox_password(); gbox_message_header(buf, MSG_REM_EMM, peer->gbox.password, local_gbox_pw); buf[10] = MSGID_REMM_DATA; i2b_buf(2, peer->gbox.id, buf +11); i2b_buf(2, local_gbox_id, buf +13); memcpy(buf +15, ep->caid, 2); memcpy(buf +17, ep->provid, 4); buf[21] = ep->emmlen; i2b_buf(4, remm_crc, buf +23); memcpy(buf +27, ep->emm, ep->emmlen); cs_log("<- send remm to: %s peer: %04X emmlength: %d crc: %08X", username(cur_client()), peer->gbox.id, ep->emmlen, remm_crc); cs_log_dump_dbg(D_EMM, buf, 27 + ep->emmlen, "<- gbox send emm, (data-len=%d):", 27 + ep->emmlen); gbox_send(cli, buf, 27 + ep->emmlen); NULLFREE(buf); return 1; } #endif