📄 camd.c
字号:
/* * Softcam plugin to VDR (C++) * * This code is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */#include <stdio.h>#include <string.h>#include <byteswap.h>#include "cc.h"#include "network.h"#include "crypto.h"#include "misc.h"#include "parse.h"#include <openssl/md5.h>#define CCVERSION "3.37"#define CCTIMEOUT 5000 // ms// -- cCardClientCommon --------------------------------------------------------class cCardClientCommon : public cCardClient, public cAES, protected cIdSet {private: bool conReply, logReply, doAES; bool exclusive; int minMsgLen; cCondVar sleepCond; cTimeMs time;protected: cNetSocket so; bool emmProcessing; char username[11], password[11]; // virtual bool Login(void); bool ParseKeyConfig(const char *config, int *num); bool ParseUserConfig(const char *config, int *num); virtual bool SendMsg(cNetSocket *so, const unsigned char *data, int len); virtual int RecvMsg(cNetSocket *so, unsigned char *data, int len, int to=-1); virtual void HandleEMMRequest(const unsigned char *buff, int len) {} virtual bool CanHandleEMM(int SysId) { return false; }public: cCardClientCommon(const char *Name, bool ConReply, bool LogReply, bool DoAES, int MinMsgLen); virtual bool Init(const char *config); virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw); virtual bool ProcessEMM(int caSys, const unsigned char *source); };cCardClientCommon::cCardClientCommon(const char *Name, bool ConReply, bool LogReply, bool DoAES, int MinMsgLen):cCardClient(Name),so(DEFAULT_CONNECT_TIMEOUT,CCTIMEOUT/1000,DEFAULT_IDLE_TIMEOUT){ conReply=ConReply; logReply=LogReply; doAES=DoAES; minMsgLen=MinMsgLen; emmProcessing=exclusive=false;}bool cCardClientCommon::ParseUserConfig(const char *config, int *num){ int startNum=*num; if(sscanf(&config[*num],":%10[^:]:%10[^:]%n",username,password,num)==2) { *num+=startNum; PRINTF(L_CC_CORE,"%s: username=%s password=%s",name,username,password);; return true; } return false;}bool cCardClientCommon::ParseKeyConfig(const char *config, int *num){ char hexkey[33]; int startNum=*num; if(sscanf(&config[*num],":%32[^:]%n",hexkey,num)==1) { *num+=startNum; PRINTF(L_CC_CORE,"%s: key=%s",name,hexkey); unsigned char binkey[16]; memset(binkey,0,sizeof(binkey)); const char *line=hexkey; int n=GetHex(line,binkey,sizeof(binkey),false); if(n!=(int)sizeof(binkey)) PRINTF(L_CC_CAMD,"warning AES key not %d bytes long",(int)sizeof(binkey)); LDUMP(L_CC_CAMD,binkey,16,"AES activated key ="); SetKey(binkey); } return true;}bool cCardClientCommon::SendMsg(cNetSocket *so, const unsigned char *data, int len){ unsigned char buff2[minMsgLen]; if(len<minMsgLen) { memcpy(buff2,data,len); memset(buff2+len,0,minMsgLen-len); data=buff2; len=minMsgLen; } unsigned char buff[len+16]; const int l=Encrypt(data,len,buff); if(l>0) { data=buff; len=l; } return cCardClient::SendMsg(so,data,len);}int cCardClientCommon::RecvMsg(cNetSocket *so, unsigned char *data, int len, int to){ int n=cCardClient::RecvMsg(so,data,len,to); if(n>0) { if(n&15) PRINTF(L_CC_CAMD,"AES crypted message length not a multiple of 16"); Decrypt(data,n); } return n;}bool cCardClientCommon::Init(const char *config){ cMutexLock lock(this); so.Disconnect(); int num=0; if(ParseStdConfig(config,&num) && ParseUserConfig(config,&num) && (!doAES || ParseKeyConfig(config,&num))) { return (emmAllowed && logReply && Immediate()) ? Login() : true; } return false;}bool cCardClientCommon::Login(void){ so.Disconnect(); if(!so.Connect(hostname,port)) return false; PRINTF(L_CC_LOGIN,"%s: connected to %s:%d (%s)",name,hostname,port,name); emmProcessing=false; unsigned char buff[128]; if(conReply) { if(RecvMsg(&so,buff,sizeof(buff))!=16) { PRINTF(L_CC_CAMD,"bad connect reply"); return false; } } memset(buff,0,32); int user_len=strlen(username)+1; memcpy(buff+1,username,user_len); int pass_len=strlen(password)+1; memcpy(buff+1+user_len+1,password,pass_len); int vers_len=strlen(CCVERSION)+1; memcpy(buff+1+user_len+pass_len+1,CCVERSION,vers_len); PRINTF(L_CC_CAMD,"login user='%s' password=hidden version=%s",username,CCVERSION); if(!SendMsg(&so,buff,32)) return false; if(emmAllowed && logReply) { PRINTF(L_CC_CAMD,"waiting for login reply ..."); int r=RecvMsg(&so,buff,sizeof(buff)); if(r>0) HandleEMMRequest(buff,r); } PRINTF(L_CC_LOGIN,"%s: login done",name); return true;}bool cCardClientCommon::ProcessEMM(int caSys, const unsigned char *source){ if(emmAllowed && CanHandleEMM(caSys)) { cMutexLock lock(this); if(MatchEMM(source)) { const int length=SCT_LEN(source); int id=msEMM.Get(source,length,0); if(id>0) { unsigned char buff[length+32]; buff[0]=0x03; buff[1]=(caSys>>8); buff[2]=(caSys&0xFF); memcpy(buff+3,((cCardIrdeto *)card)->hexSer,3); buff[6]=((cCardIrdeto *)card)->hexBase; memcpy(&buff[7],source,length); //PRINTF(L_CC_CAMD,"%s: sending EMM for caid 0x%04X",name,caSys); SendMsg(&so,buff,length+7); msEMM.Cache(id,true,0); } return true; } } return false;}bool cCardClientCommon::ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw){ Lock(); bool res=false; while(exclusive) sleepCond.Wait(*this); if((so.Connected() || Login()) && (!emmProcessing || CanHandle(ecm->caId))) { const int length=SCT_LEN(source); unsigned char buff[length+32]; int n; while((n=RecvMsg(&so,buff,16,0))>0) HandleEMMRequest(buff,n); buff[0]=0x02; buff[1]=(ecm->caId>>8); buff[2]=(ecm->caId&0xFF); memset(&buff[3],0,4); memcpy(&buff[7],source,length); if(SendMsg(&so,buff,length+7)) { exclusive=true; time.Set(CCTIMEOUT); do { sleepCond.TimedWait(*this,50); while((n=RecvMsg(&so,buff,32,0))>0) { if(n>=21 && buff[0]==2) { if(!CheckNull(buff+5,16)) { if(!res) { memcpy(cw,buff+5,16); res=true; } else PRINTF(L_CC_CAMD,"unexpected CW packet"); } else { PRINTF(L_CC_ECM,"%s: server is unable to handle ECM",name); n=-1; break; } } else HandleEMMRequest(buff,n); } } while(!res && n>=0 && !time.TimedOut()); if(!res && time.TimedOut()) PRINTF(L_CC_ECM,"%s: CW request timed out",name); exclusive=false; sleepCond.Broadcast(); } } Unlock(); return res;}// -- cCardClientCamd33 --------------------------------------------------------class cCardClientCamd33 : public cCardClientCommon {private: int CAID; unsigned char lastEmmReq[32];protected: virtual void HandleEMMRequest(const unsigned char *buff, int len); virtual bool CanHandleEMM(int SysId);public: cCardClientCamd33(const char *Name); virtual bool CanHandle(unsigned short SysId); };static cCardClientLinkReg<cCardClientCamd33> __camd33("Camd33");cCardClientCamd33::cCardClientCamd33(const char *Name):cCardClientCommon(Name,true,true,true,0){ CAID=0; memset(lastEmmReq,0,sizeof(lastEmmReq));}bool cCardClientCamd33::CanHandle(unsigned short SysId){ return CanHandleEMM(SysId) || cCardClient::CanHandle(SysId);}bool cCardClientCamd33::CanHandleEMM(int SysId){ return (emmProcessing && SysId==CAID);}void cCardClientCamd33::HandleEMMRequest(const unsigned char *buff, int len){ if(len>=13 && buff[0]==0 && !CheckNull(buff,len) && memcmp(buff,lastEmmReq,13)) { emmProcessing=false; CAID=buff[1]*256+buff[2]; ResetIdSet(); switch(CAID>>8) { case 0x17: case 0x06: SetCard(new cCardIrdeto(buff[6],&buff[3])); AddProv(new cProviderIrdeto(0,&buff[7])); AddProv(new cProviderIrdeto(2,&buff[10])); memcpy(lastEmmReq,buff,13); PRINTF(L_CC_LOGIN,"%s: CAID: %04x HexSerial: %02X%02X%02X, HexBase: %02X",name,CAID,buff[3],buff[4],buff[5],buff[6]); PRINTF(L_CC_LOGIN,"%s: Provider00: %02X%02X%02X, Provider10: %02X%02X%02X",name,buff[7],buff[8],buff[9],buff[10],buff[11],buff[12]); if(!emmAllowed) PRINTF(L_CC_EMM,"%s: EMM disabled from config",name); emmProcessing=true; break; } }}// -- cCardClientCardd ---------------------------------------------------------class cCardClientCardd : public cCardClientCommon {public: cCardClientCardd(const char *Name); };static cCardClientLinkReg<cCardClientCardd> __cardd("Cardd");cCardClientCardd::cCardClientCardd(const char *Name):cCardClientCommon(Name,false,true,false,96){}// -- cCardClientBuffy ---------------------------------------------------------#define MAX_CAIDS 16class cCardClientBuffy : public cCardClientCommon {private: unsigned short CAIDs[MAX_CAIDS], numCAIDs;protected: virtual bool Login(void);public: cCardClientBuffy(const char *Name); virtual bool Init(const char *config); virtual bool CanHandle(unsigned short SysId); };static cCardClientLinkReg<cCardClientBuffy> __buffy("Buffy");cCardClientBuffy::cCardClientBuffy(const char *Name):cCardClientCommon(Name,true,false,true,0){}bool cCardClientBuffy::Init(const char *config){ cMutexLock lock(this); if(cCardClientCommon::Init(config)) { return Immediate() ? Login() : true; } return false;}bool cCardClientBuffy::CanHandle(unsigned short SysId){ cMutexLock lock(this); for(int i=0; i<numCAIDs; i++) if(CAIDs[i]==SysId) return true; return false;}bool cCardClientBuffy::Login(void){ cMutexLock lock(this); if(!cCardClientCommon::Login()) return false; unsigned char buff[128]; memset(buff,0,sizeof(buff)); buff[0]=0x0A; if(!SendMsg(&so,buff,32)) return false; int n=RecvMsg(&so,buff,sizeof(buff)); if(n<0) return false; for(int i=1; i<n && numCAIDs<MAX_CAIDS; i+=2) { unsigned short caid=(buff[i+1]<<8)+buff[i]; if(caid==0xFFFF) break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -