2 Star 1 Fork 0

长江/oscam

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
module-scam.c 25.43 KB
一键复制 编辑 原始数据 按行查看 历史
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111
#define MODULE_LOG_PREFIX "scam"
#include "globals.h"
#ifdef MODULE_SCAM
#include "oscam-client.h"
#include "oscam-ecm.h"
#include "oscam-net.h"
#include "oscam-string.h"
#include "oscam-reader.h"
#include "oscam-lock.h"
#include "oscam-time.h"
#include "oscam-chk.h"
#include "cscrypt/des.h"
struct scam_data
{
uchar enckey[8];
uchar deckey[8];
uint8_t enc_xor_offset;
uint8_t dec_xor_offset;
uint8_t login_pending;
char login_username[64];
uint16_t version;
};
static inline void xxor(uint8_t *data, int32_t len, const uint8_t *v1, const uint8_t *v2)
{
uint32_t i;
switch(len)
{
case 16:
for(i = 8; i < 16; ++i)
{
data[i] = v1[i] ^ v2[i];
}
case 8:
for(i = 4; i < 8; ++i)
{
data[i] = v1[i] ^ v2[i];
}
case 4:
for(i = 0; i < 4; ++i)
{
data[i] = v1[i] ^ v2[i];
}
break;
default:
while(len--) { *data++ = *v1++ ^ *v2++; }
break;
}
}
static void scam_generate_deskey(char *keyString, uint8_t *desKey)
{
uint8_t iv[8], *tmpKey;
int32_t i, passLen, alignedPassLen;
uint32_t key_schedule[32];
memset(iv, 0, 8);
memset(desKey, 0, 8);
passLen = keyString == NULL ? 0 : strlen(keyString);
if(passLen > 1024) {
passLen = 1024;
}
alignedPassLen = (passLen + 7) & -8;
if(alignedPassLen == 0) alignedPassLen = 8;
if(!cs_malloc(&tmpKey, alignedPassLen)) {
return;
}
if(passLen == 0) {
memset(tmpKey, 0xAA, 8);
passLen = 8;
}
else {
memcpy(tmpKey, keyString, passLen);
}
for(i=0; i<alignedPassLen-passLen; i++) {
tmpKey[passLen+i] = (uint8_t)i;
}
xxor(desKey,8,tmpKey,iv);
for(i=0; i<alignedPassLen; i+=8) {
des_set_key(&tmpKey[i], key_schedule);
des(&tmpKey[i], key_schedule, 1);
xxor(desKey,8,desKey,&tmpKey[i]);
}
NULLFREE(tmpKey);
}
static void scam_encrypt_packet(uint8_t *packet, uint32_t packetLength, uint8_t *key, uint32_t dataLength, uint32_t dataOffset, uint8_t *xorOffset)
{
uint8_t iv[8];
uint32_t i;
memset(iv, 0, 8);
des_cbc_encrypt(packet + dataOffset, iv, key, dataLength);
for(i=0; i<packetLength; i++) {
key[*xorOffset] ^= packet[i];
*xorOffset = (*xorOffset + 1) & 7;
}
}
static void scam_decrypt_packet(uint8_t *packet, uint32_t packetLength, uint8_t *key, uint32_t dataLength, uint32_t dataOffset, uint8_t *xorOffset)
{
uint8_t tmpKey[8], iv[8];
uint32_t i;
memcpy(tmpKey, key, 8);
memset(iv, 0, 8);
for(i=0; i<packetLength; i++) {
tmpKey[*xorOffset] ^= packet[i];
*xorOffset = (*xorOffset + 1) & 7;
}
des_cbc_decrypt(packet + dataOffset, iv, key, dataLength);
memcpy(key, tmpKey, 8);
}
static void scam_decode_length(uint8_t *packet, uint32_t *dataLength, uint32_t *dataOffset)
{
uint32_t i, n;
if(packet[1] & 0x80) {
n = packet[1]&~0x80;
*dataLength = 0;
for(i=0; i<n; i++) {
*dataLength = (*dataLength << 8) | packet[2+i];
}
*dataOffset = 2 + n;
}
else {
*dataLength = packet[1];
*dataOffset = 2;
}
}
static uint32_t scam_get_length_data_length(uint8_t *packet)
{
if(packet[1] & 0x80) {
return packet[1]&~0x80;
}
else {
return 1;
}
}
static void scam_encode_length(uint32_t len, uint8_t *data, uint8_t *dataLen)
{
if(len < 128)
{
data[0] = (uint8_t)len;
*dataLen = 1;
}
else if (len < 256 )
{
data[0] = 0x81;
data[1] = (uint8_t)len;
*dataLen = 2;
}
else if (len < 65536 ) {
data[0] = 0x82;
data[1] = (uint8_t)(len>>8);
data[2] = (uint8_t)(len&0xFF);
*dataLen = 3;
}
else if (len < 16777216 )
{
data[0] = 0x83;
data[1] = (uint8_t)(len>>16);
data[2] = (uint8_t)((len>>8)&0xFF);
data[3] = (uint8_t)(len&0xFF);
*dataLen = 4;
}
else
{
data[0] = 0x84;
data[1] = (uint8_t)(len>>24);
data[2] = (uint8_t)((len>>16)&0xFF);
data[3] = (uint8_t)((len>>8)&0xFF);
data[4] = (uint8_t)(len&0xFF);
*dataLen = 5;
}
}
static void scam_client_close(struct s_client *cl, int32_t call_conclose)
{
struct s_reader *rdr = cl->reader;
if(!rdr) { return; }
if(rdr) { rdr->tcp_connected = 0; }
if(rdr) { rdr->card_status = NO_CARD; }
if(rdr) { rdr->last_s = rdr->last_g = 0; }
if(cl) { cl->last = 0; }
if(call_conclose) //clears also pending ecms!
{ network_tcp_connection_close(rdr, "close"); }
else
{
if(cl->udp_fd)
{
close(cl->udp_fd);
cl->udp_fd = 0;
cl->pfd = 0;
}
}
}
static int32_t scam_send(struct s_client *cl, uchar *buf, uint32_t len)
{
uchar *mbuf, lenData[5];
uint8_t lenDataLen = 0, paddingLen = 0;
uint16_t crc = 0;
int32_t result, packetLen;
struct scam_data *scam = cl->scam;
if(scam == NULL) { return 0; }
if(len == 0) { return 0; }
paddingLen = 8 - ((4+len) % 8);
if(paddingLen == 8) {
paddingLen = 0;
}
else if(paddingLen > 0 && paddingLen < 3) {
paddingLen += 8;
}
scam_encode_length(4+len+paddingLen, lenData, &lenDataLen);
if(lenDataLen == 0) { return -1; }
packetLen = 1+lenDataLen+4+len+paddingLen;
if(!cs_malloc(&mbuf, packetLen)) { return -1; }
mbuf[0] = 0x0F;
memcpy(&mbuf[1], lenData, lenDataLen);
mbuf[1+lenDataLen] = 0x10;
mbuf[1+lenDataLen+1] = 0x02;
memcpy(&mbuf[1+lenDataLen+4], buf, len);
if(paddingLen > 0) {
mbuf[1+lenDataLen+4+len] = 0x7F;
mbuf[1+lenDataLen+4+len+1] = paddingLen - 2;
get_random_bytes(mbuf+1+lenDataLen+4+len+2, paddingLen - 2);
}
crc = ccitt_crc(mbuf+1+lenDataLen+4, len+paddingLen, 0xFFFF, 0);
i2b_buf(2, crc, &mbuf[1+lenDataLen+2]);
scam_encrypt_packet(mbuf, packetLen, scam->enckey, 4+len+paddingLen, 1+lenDataLen, &scam->enc_xor_offset);
result = send(cl->pfd, mbuf, packetLen, 0);
NULLFREE(mbuf);
return (result);
}
static int32_t scam_msg_recv(struct s_client *cl, uint8_t *buf, int32_t maxlen)
{
int32_t len;
int32_t handle = cl->udp_fd;
struct scam_data *scam = cl->scam;
if(scam == NULL) { return 0; }
if(handle <= 0 || maxlen < 3)
{ cs_log("scam_msg_recv: fd is 0"); return -1; }
len = cs_recv(handle, buf, 2, MSG_WAITALL);
if(len != 2) // invalid header length read
{
if(len <= 0)
{ cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "disconnected by remote server"); }
else
{ cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "invalid header length (expected 2, read %d)", len); }
return -1;
}
if(buf[0] != 0x0F)
{
cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "invalid packet tag");
return 0;
}
int32_t headerSize = buf[1]&0x80 ? (2 + (buf[1]&~0x80)) : 2;
if(headerSize > 2) {
if(maxlen < headerSize+1) { return -1; }
len = cs_recv(handle, buf+2, headerSize-2, MSG_WAITALL);
if(len != headerSize-2) // invalid header length read
{
if(len <= 0)
{ cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "disconnected by remote server"); }
else
{ cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "invalid header length (expected %d, read %d)", headerSize, 2+len); }
return -1;
}
}
uint32_t dataLength, dataOffset;
scam_decode_length(buf, &dataLength, &dataOffset);
if(dataLength) // check if any data is expected in msg
{
if(dataLength%8 != 0)
{
cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "message data has invalid size (size=%d)", dataLength);
return 0;
}
if(headerSize+dataLength > (uint32_t)maxlen)
{
cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "message too big (size=%d max=%d)", headerSize+dataLength, maxlen);
return 0;
}
len = cs_recv(handle, buf + dataOffset, dataLength, MSG_WAITALL);
if((uint32_t)len != dataLength)
{
if(len <= 0) {
cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "disconnected by remote");
}
else {
cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "invalid message length read (expected %d, read %d)", dataLength, len);
}
return -1;
}
scam_decrypt_packet(buf, headerSize+dataLength, scam->deckey, dataLength, dataOffset, &scam->dec_xor_offset);
}
return headerSize+dataLength;
}
static int32_t scam_recv(struct s_client *cl, uchar *buf, int32_t len)
{
int32_t n;
struct s_reader *rdr = (cl->typ == 'c') ? NULL : cl->reader;
if(buf == NULL || len <= 0)
{ return -1; }
n = scam_msg_recv(cl, buf, len); // recv and decrypt msg
if(n <= 0)
{
cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "connection closed by %s, n=%d.", remote_txt(), n);
if(rdr)
{
scam_client_close(cl, 1);
}
else
{
cs_disconnect_client(cl);
}
cs_sleepms(150);
n = -1;
}
else
{
cl->last = time(NULL); // last client action is now
if(rdr) { rdr->last_g = time(NULL); } // last reader receive is now
}
return n;
}
//scam client functions
static int32_t scam_client_init(struct s_client *cl);
static int32_t scam_client_connect(void)
{
struct s_client *cl = cur_client();
if(cl->reader->tcp_connected < 2 && scam_client_init(cl) < 0)
{ return 0; }
if(!cl->udp_fd)
{ return 0; }
return 1;
}
static void scam_client_idle(void)
{
struct s_client *client = cur_client();
struct s_reader *rdr = client->reader;
time_t now = time(NULL);
if(!rdr) { return; }
if(rdr->tcp_ito > 0)
{
int32_t time_diff;
time_diff = llabs(now - rdr->last_s);
if(time_diff > (rdr->tcp_ito))
{
network_tcp_connection_close(rdr, "inactivity");
return;
}
}
else if(rdr->tcp_ito == -1)
{
scam_client_connect();
return;
}
}
static void scam_client_recv_caid(uint8_t *buf, uint32_t len)
{
uint16_t caid;
if(len < 3) {
return;
}
caid = buf[1] << 8 | buf[2];
if(buf[0]) {
cs_log("scam server has card: %04X", caid);
}
else {
cs_log("scam server no longer has card: %04X", caid);
}
}
static void scam_client_recv_server_version(uint8_t *buf, uint32_t len)
{
uint32_t pos = 0, dataLength = 0, dataOffset = 0, usedLen = 0;
char versionString[128];
uint16_t versionShort = 0;
versionString[0] = 0;
scam_decode_length(buf, &dataLength, &dataOffset);
while(pos+dataOffset+dataLength-1 < len)
{
switch(buf[pos]) {
case 0x01: // version string
usedLen = dataLength;
if(usedLen > 127) {
usedLen = 127;
}
memcpy(versionString, buf+dataOffset, usedLen);
versionString[usedLen] = 0;
break;
case 0x0A: // version short
if(dataLength != 2) break;
versionShort = (buf[pos+dataOffset] << 8) | buf[pos+dataOffset+1];
break;
default:
cs_log_dbg(D_READER, "unknown server version packet tag %X", buf[pos]);
break;
}
pos += dataOffset+dataLength;
if(pos+2 < len && pos+1+scam_get_length_data_length(buf+pos) < len) {
scam_decode_length(buf+pos, &dataLength, &dataOffset);
}
else {
break;
}
}
cs_log("scam server version: %s (%d)", versionString, versionShort);
}
static void scam_client_recv_dcw(struct s_client *cl, uint8_t *buf, uint32_t len, uint8_t *dcw, int32_t *ecm_task_idx, int32_t *rc)
{
// 00C00000 enimga namespace
// 0455 tsid
// 0001 onid
// 151A srvid
// 200081 ???
// 943E85577035C469 dcw1
// C73882811721E31B dcw2
if(len != 29) {
cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "unknown server dcw packet length %d", len);
return;
}
*ecm_task_idx = b2i(4, &buf[0]); // we store idx here instead of ens
memcpy(dcw, &buf[13], 16);
*rc = 1;
}
static void scam_client_send_hello(struct s_client *cl)
{
uchar mbuf[70];
uint32_t usernameLen, i = 0;
struct s_reader *rdr = cl->reader;
struct scam_data *scam = cl->scam;
if(scam == NULL) { return; }
if(!rdr) { return; }
usernameLen = strlen(rdr->r_usr);
if(usernameLen > 63) { // because rdr->r_usr is max. 63+1 chars
usernameLen = 63;
}
mbuf[i++] = 0x46; // client hello data type
mbuf[i++] = 6 + usernameLen; // will never exceed 63+6 = 69 bytes (<127 bytes)
// client version
mbuf[i++] = 0xA0; // client version data type
mbuf[i++] = 0x02; // data length (2)
mbuf[i++] = 0x00; // version ( 0x0007)
mbuf[i++] = 0x07;
//username
mbuf[i++] = 0xA1; // username data type
mbuf[i++] = (uint8_t)usernameLen;
memcpy(mbuf+i, rdr->r_usr, usernameLen);
mbuf[i+usernameLen] = 0;
scam_send(cl, mbuf, 8+usernameLen);
scam_generate_deskey(rdr->r_pwd, scam->enckey);
scam_generate_deskey(rdr->r_pwd, scam->deckey);
scam->enc_xor_offset = 0;
scam->dec_xor_offset = 0;
}
static int32_t scam_client_send_ecm(struct s_client *cl, ECM_REQUEST *er)
{
// 2481A5 310A
// 00C00000 enimga namespace
// 0455 tsid
// 0001 onid
// 151A srvid
// 3002
// 1843 caid
// 3304
// 66A1AE16 pat/pmt crc? we currently fill it with chid
// 348189
// 8130.. ecm
// 3501
// 02 needed dcws?
uchar *mbuf, packetLenData[5], ecmLenData[5];
uint32_t i = 0, ret = 0, dataLength = 0, packetLength = 0;
uint8_t pLenDataLen = 0, eLenDataLen = 0;
if(!scam_client_connect())
{ return (-1); }
scam_encode_length(er->ecmlen, ecmLenData, &eLenDataLen);
dataLength = 23 + eLenDataLen + er->ecmlen + 3;
scam_encode_length(dataLength, packetLenData, &pLenDataLen);
packetLength = 1 + pLenDataLen + dataLength;
if(!cs_malloc(&mbuf, packetLength))
{ return -1; }
mbuf[i++] = 0x24; // ecm request data type
memcpy(mbuf+i, packetLenData, pLenDataLen); i += pLenDataLen;
mbuf[i++] = 0x31; // channel info data type
mbuf[i++] = 0x0A; // size is always 0x0A
//i2b_buf(4, er->ens, mbuf+i); i += 4;
i2b_buf(4, er->idx, mbuf+i); i += 4; // we store idx instead of ens here
i2b_buf(2, er->tsid, mbuf+i); i += 2;
i2b_buf(2, er->onid, mbuf+i); i += 2;
i2b_buf(2, er->srvid, mbuf+i); i += 2;
mbuf[i++] = 0x30; // caid data type
mbuf[i++] = 0x02; // size is always 0x02
i2b_buf(2, er->caid, mbuf+i); i += 2;
mbuf[i++] = 0x33; // ??? data type
mbuf[i++] = 0x04; // size is always 0x04
i2b_buf(2, er->chid, mbuf+i); i += 4;
mbuf[i++] = 0x34; // ecm data type
memcpy(mbuf+i, ecmLenData, eLenDataLen); i += eLenDataLen;
memcpy(mbuf+i, er->ecm, er->ecmlen); i += er->ecmlen;
mbuf[i++] = 0x35; // ??? data type
mbuf[i++] = 0x01; // size is always 0x01
mbuf[i++] = 0x02; // unknown value
ret = scam_send(cl, mbuf, packetLength);
cs_log_dbg(D_TRACE, "scam: sending ecm");
cs_log_dump_dbg(D_CLIENT, mbuf, packetLength, "ecm:");
NULLFREE(mbuf);
return ((ret < 1) ? (-1) : 0);
}
static int32_t scam_client_init(struct s_client *cl)
{
int32_t handle;
handle = network_tcp_connection_open(cl->reader);
if(handle < 0) {
cl->reader->last_s = 0; // set last send to zero
cl->reader->last_g = 0; // set last receive to zero
cl->last = 0; // set last client action to zero
return (0);
}
if(cl->scam) {
memset(cl->scam, 0, sizeof(struct scam_data));
}
if(!cl->scam && !cs_malloc(&cl->scam, sizeof(struct scam_data))) {
return 0;
}
cs_log("scam: proxy %s:%d (fd=%d)",
cl->reader->device, cl->reader->r_port, cl->udp_fd);
cl->reader->tcp_connected = 2;
cl->reader->card_status = CARD_INSERTED;
cl->reader->last_g = cl->reader->last_s = time((time_t *)0);
cs_log_dbg(D_CLIENT, "scam: last_s=%ld, last_g=%ld", cl->reader->last_s, cl->reader->last_g);
cl->pfd = cl->udp_fd;
scam_client_send_hello(cl);
return (0);
}
static int32_t scam_client_handle(struct s_client *cl, uchar *dcw, int32_t *rc, uchar *buf, int32_t n)
{
uint32_t pos = 0, packetLength = 0, packetOffset = 0, dataLength = 0, dataOffset = 0;
int32_t ret = -1;
if(n < 3) {
return (-1);
}
scam_decode_length(buf, &packetLength, &packetOffset);
pos += packetOffset;
if(pos+2 < (uint32_t)n && pos+1+scam_get_length_data_length(buf+pos) < (uint32_t)n) {
scam_decode_length(buf+pos, &dataLength, &dataOffset);
}
else {
return (-1);
}
while(pos+dataOffset+dataLength-1 < (uint32_t)n)
{
switch(buf[pos]) {
case 0x10: // checksum
if(dataLength != 2) { break; }
if(b2i(2, &buf[pos+dataOffset]) != ccitt_crc(buf+pos+dataOffset+2, n-pos-dataOffset-2, 0xFFFF, 0)) {
cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "sent packet with invalid checksum");
return (-1);
}
break;
case 0x20: // caid list
scam_client_recv_caid(buf+pos+dataOffset, dataLength);
break;
case 0x45: // server version
scam_client_recv_server_version(buf+pos+dataOffset, dataLength);
break;
case 0x63: // dcw
scam_client_recv_dcw(cl, buf+pos+dataOffset, dataLength, dcw, &ret, rc);
break;
case 0x7F: // padding
break;
default:
cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "unknown scam server packet %X", buf[pos]);
break;
}
pos += dataOffset+dataLength;
if(pos+2 < (uint32_t)n && pos+1+scam_get_length_data_length(buf+pos) < (uint32_t)n) {
scam_decode_length(buf+pos, &dataLength, &dataOffset);
}
else {
break;
}
}
return ret;
}
// scam server functions
static uint8_t scam_server_authip_client(struct s_client *cl)
{
if(cfg.scam_allowed && !check_ip(cfg.scam_allowed, cl->ip))
{
cs_log("scam: IP not allowed");
cs_auth_client(cl, (struct s_auth *)0, NULL);
cs_disconnect_client(cl);
return 0;
}
return 1;
}
static void scam_server_init(struct s_client *cl)
{
if(!cl->init_done)
{
if(IP_ISSET(cl->ip))
{ cs_log("scam: new connection from %s", cs_inet_ntoa(cl->ip)); }
if(scam_server_authip_client(cl)) {
if(cl->scam) {
memset(cl->scam, 0, sizeof(struct scam_data));
}
if(cl->scam || cs_malloc(&cl->scam, sizeof(struct scam_data))) {
cl->init_done = 1;
}
}
}
return;
}
static void scam_server_recv_ecm(struct s_client *cl, uchar *buf, int32_t len)
{
uint32_t pos = 0, dataLength = 0, dataOffset = 0, usedLen = 0;
ECM_REQUEST *er;
uint8_t gotCaid = 0, gotEcm = 0;
if(len < 1) {
return;
}
if(!(er = get_ecmtask()))
{ return; }
scam_decode_length(buf, &dataLength, &dataOffset);
while(pos+dataOffset+dataLength-1 < (uint32_t)len)
{
switch(buf[pos]) {
case 0x31: // channel data
if(dataLength != 0x0A) break;
er->ens = b2i(4, buf+pos+dataOffset);
er->tsid = b2i(2, buf+pos+dataOffset+4);
er->onid = b2i(2, buf+pos+dataOffset+6);
er->srvid = b2i(2, buf+pos+dataOffset+8);
break;
case 0x30: // caid
if(dataLength != 0x02) break;
er->caid = b2i(2, buf+pos+dataOffset);
gotCaid = 1;
break;
case 0x33: // unknown
break;
case 0x34: // ecm
usedLen = dataLength;
if(usedLen > MAX_ECM_SIZE) {
break;
}
er->ecmlen = usedLen;
memcpy(er->ecm, buf+pos+dataOffset, usedLen);
gotEcm = 1;
break;
case 0x35: // unknown
break;
default:
cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "sent unknown scam client ecm tag %X", buf[pos]);
break;
}
pos += dataOffset+dataLength;
if(pos+2 < (uint32_t)len && pos+1+scam_get_length_data_length(buf+pos) < (uint32_t)len) {
scam_decode_length(buf+pos, &dataLength, &dataOffset);
}
else {
break;
}
}
if(gotCaid && gotEcm) {
get_cw(cl, er);
}
else {
NULLFREE(er);
cs_log("WARNING: ECM-request corrupt");
}
}
static void scam_caidlist_add(uint16_t *caidlist, uint32_t listsize, uint32_t *count, uint16_t caid)
{
uint32_t i;
uint8_t exists = 0;
if(*count >= listsize) {
return;
}
for(i=0; i<*count; i++) {
if(caidlist[i] == caid) {
exists = 1;
break;
}
}
if(!exists) {
caidlist[*count] = caid;
(*count)++;
}
}
static void scam_server_send_caidlist(struct s_client *cl)
{
uchar mbuf[5];
int32_t j;
uint32_t i = 0;
uint16_t caids[55];
uint32_t cardcount = 0;
struct s_reader *rdr = NULL;
cs_readlock(__func__, &readerlist_lock);
for(rdr = first_active_reader; rdr; rdr = rdr->next)
{
if(rdr->caid && chk_ctab(rdr->caid, &cl->ctab)) {
scam_caidlist_add(caids, ARRAY_SIZE(caids), &cardcount, rdr->caid);
}
for(j = 0; j < rdr->ctab.ctnum; j++) {
CAIDTAB_DATA *d = &rdr->ctab.ctdata[j];
if(d->caid && chk_ctab(d->caid, &cl->ctab)) {
scam_caidlist_add(caids, ARRAY_SIZE(caids), &cardcount, d->caid);
}
}
}
cs_readunlock(__func__, &readerlist_lock);
for(j=0; j < (int32_t)cardcount; j++) {
i = 0;
mbuf[i++] = 0x20; // caid data type
mbuf[i++] = 0x03; // length
mbuf[i++] = 0x01; // active card
i2b_buf(2, caids[j], mbuf+i);
scam_send(cl, mbuf, 5);
}
}
static void scam_server_send_serverversion(struct s_client *cl)
{
uchar mbuf[64];
uint32_t i = 0;
char *version = "scam/3.60 oscam";
uint8_t vlen = strlen(version);
mbuf[i++] = 0x45; // server version data type
mbuf[i++] = 2+vlen+4; // will never exceed 127 bytes
mbuf[i++] = 0x01; // server version string data type
mbuf[i++] = vlen; // will never exceed 127 bytes
memcpy(mbuf+i, version, vlen); i += vlen;
mbuf[i++] = 0x0A; // server version short data type
mbuf[i++] = 0x02; // is always 0x02
i2b_buf(2, 0x7, mbuf+i);
scam_send(cl, mbuf, 2+2+vlen+4);
}
static void scam_server_recv_auth(struct s_client *cl, uchar *buf, int32_t len)
{
uint32_t pos = 0, dataLength = 0, dataOffset = 0, usedLen = 0;
uint8_t userok = 0;
struct s_auth *account;
struct scam_data *scam = cl->scam;
if(scam == NULL) { return; }
scam->login_username[0] = 0;
if(len < 1) {
return;
}
scam_decode_length(buf, &dataLength, &dataOffset);
while(pos+dataOffset+dataLength-1 < (uint32_t)len)
{
switch(buf[pos]) {
case 0xA0: // version short
if(dataLength != 2) break;
scam->version = (buf[pos+dataOffset] << 8) | buf[pos+dataOffset+1];
break;
case 0xA1: // username string
usedLen = dataLength;
if(usedLen > 64) {
usedLen = 63;
}
memcpy(scam->login_username, buf+pos+dataOffset, usedLen);
scam->login_username[usedLen] = 0;
break;
default:
cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "unknown client auth packet tag %X", buf[pos]);
break;
}
pos += dataOffset+dataLength;
if(pos+2 < (uint32_t)len && pos+1+scam_get_length_data_length(buf+pos) < (uint32_t)len) {
scam_decode_length(buf+pos, &dataLength, &dataOffset);
}
else {
break;
}
}
for(account = cfg.account; account; account = account->next)
{
if(streq(scam->login_username, account->usr))
{
userok = 1;
break;
}
}
if(!userok)
{
cs_auth_client(cl, (struct s_auth *)0, NULL);
cs_disconnect_client(cl);
return;
}
scam->login_pending = 1;
scam_generate_deskey(account->pwd, scam->enckey);
scam_generate_deskey(account->pwd, scam->deckey);
scam->enc_xor_offset = 0;
scam->dec_xor_offset = 0;
scam_server_send_caidlist(cl);
scam_server_send_serverversion(cl);
}
static void scam_server_send_dcw(struct s_client *cl, ECM_REQUEST *er)
{
uchar mbuf[31];
uint32_t i = 0;
if(!(er->rc < E_NOTFOUND)) {
return;
}
mbuf[i++] = 0x63; // dcw data type
mbuf[i++] = 0x1D; // fixed sized < 127
i2b_buf(4, er->ens, mbuf+i); i += 4;
i2b_buf(2, er->tsid, mbuf+i); i += 2;
i2b_buf(2, er->onid, mbuf+i); i += 2;
i2b_buf(2, er->srvid, mbuf+i); i += 2;
mbuf[i++] = 0x20; // unknown
mbuf[i++] = 0x00; // unknown
mbuf[i++] = 0x81; // unknown
memcpy(mbuf+i, er->cw, 16);
scam_send(cl, mbuf, 31);
}
static void *scam_server_handle(struct s_client *cl, uchar *buf, int32_t n)
{
uint32_t pos = 0, packetLength = 0, packetOffset = 0, dataLength = 0, dataOffset = 0;
struct s_auth *account;
struct scam_data *scam;
if(n < 3)
{ return NULL; }
if(!cl->init_done)
{
if(!scam_server_authip_client(cl)) { return NULL; }
if(cl->scam) {
memset(cl->scam, 0, sizeof(struct scam_data));
}
if(cl->scam == NULL && !cs_malloc(&cl->scam, sizeof(struct scam_data))) {
return NULL;
}
cl->init_done = 1;
}
scam = cl->scam;
if(scam == NULL) {
return NULL;
}
scam_decode_length(buf, &packetLength, &packetOffset);
pos += packetOffset;
if(scam->login_pending && packetLength > 1 && (buf[pos] != 0x10 || buf[pos+1] != 0x02)) {
scam->login_pending = 0;
cs_auth_client(cl, (struct s_auth *)0, NULL);
cs_disconnect_client(cl);
return NULL;
}
if(pos+2 < (uint32_t)n && pos+1+scam_get_length_data_length(buf+pos) < (uint32_t)n) {
scam_decode_length(buf+pos, &dataLength, &dataOffset);
}
else {
return NULL;
}
while(pos+dataOffset+dataLength-1 < (uint32_t)n)
{
switch(buf[pos]) {
case 0x10: // checksum
if(dataLength != 2) { break; }
if(b2i(2, &buf[pos+dataOffset]) != ccitt_crc(buf+pos+dataOffset+2, n-pos-dataOffset-2, 0xFFFF, 0)) {
cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "sent packet with invalid checksum");
return NULL;
}
if(scam->login_pending) {
for(account = cfg.account; account; account = account->next) {
if(streq(scam->login_username, account->usr)) {
scam->login_pending = 0;
if(!cs_auth_client(cl, account, NULL)) {
cs_log("scam client login: %s version: %d", scam->login_username, scam->version);
}
else {
cs_disconnect_client(cl);
}
break;
}
}
if(scam->login_pending)
{
scam->login_pending = 0;
cs_auth_client(cl, (struct s_auth *)0, NULL);
cs_disconnect_client(cl);
return NULL;
}
}
break;
case 0x46: // client auth
scam_server_recv_auth(cl, buf+pos+dataOffset, dataLength);
break;
case 0x24: // ecm request
scam_server_recv_ecm(cl, buf+pos+dataOffset, dataLength);
break;
case 0x7F: // padding
break;
default:
cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "sent unknown scam client packet %X", buf[pos]);
break;
}
pos += dataOffset+dataLength;
if(pos+2 < (uint32_t)n && pos+1+scam_get_length_data_length(buf+pos) < (uint32_t)n) {
scam_decode_length(buf+pos, &dataLength, &dataOffset);
}
else {
break;
}
}
return NULL;
}
void scam_cleanup(struct s_client *cl)
{
NULLFREE(cl->scam);
}
void module_scam(struct s_module *ph)
{
ph->desc = "scam";
ph->type = MOD_CONN_TCP;
ph->listenertype = LIS_SCAM;
ph->num = R_SCAM;
ph->large_ecm_support = 1;
IP_ASSIGN(ph->s_ip, cfg.scam_srvip);
ph->ptab.nports = 1;
ph->ptab.ports[0].s_port = cfg.scam_port;
// server + client
ph->recv = scam_recv;
ph->cleanup = scam_cleanup;
// server
ph->s_init = scam_server_init;
ph->s_handler = scam_server_handle;
ph->send_dcw = scam_server_send_dcw;
// client
ph->c_init = scam_client_init;
ph->c_idle = scam_client_idle;
ph->c_recv_chk = scam_client_handle;
ph->c_send_ecm = scam_client_send_ecm;
}
#endif
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/4a02/oscam.git
git@gitee.com:4a02/oscam.git
4a02
oscam
oscam
master

搜索帮助