470 lines
13 KiB
C
470 lines
13 KiB
C
#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
|
|
|