oscam-2.26.01-11942-802-wit.../module-gbox-remm.c
2026-02-24 21:37:51 +00:00

470 lines
13 KiB
C
Executable File

#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