|
SASC-NG
DVBSoftCAM
|
00001 /* 00002 * Softcam plugin to VDR (C++) 00003 * 00004 * This code is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This code is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html 00018 */ 00019 00020 // initialy written by anetwolf anetwolf@hotmail.com 00021 // based on crypto & protocol information from _silencer 00022 // EMM & cmd 05 handling based on contribution from appiemulder 00023 // cmd 05/0b/0c/0d handling based on oscam sources 00024 00025 #include <stdio.h> 00026 #include <stdlib.h> 00027 #include <unistd.h> 00028 00029 #include <openssl/sha.h> 00030 00031 #include "cc.h" 00032 #include "parse.h" 00033 #include "crypto.h" 00034 #include "helper.h" 00035 #include "version.h" 00036 00037 static const char *cccamstr="CCcam"; 00038 00039 // -- cCCcamCrypt -------------------------------------------------------------- 00040 00041 class cCCcamCrypt { 00042 private: 00043 unsigned char keytable[256]; 00044 unsigned char state, counter, sum; 00045 bool log; 00046 // 00047 static void Swap(unsigned char *p1, unsigned char *p2); 00048 public: 00049 void Init(const unsigned char *key, int length, bool l=false); 00050 void Decrypt(const unsigned char *in, unsigned char *out, int length); 00051 void DecryptRC4(const unsigned char *in, unsigned char *out, int length); 00052 void Encrypt(const unsigned char *in, unsigned char *out, int length); 00053 static void ScrambleDcw(unsigned char *data, const unsigned char *nodeid, unsigned int shareid); 00054 static bool DcwChecksum(const unsigned char *data); 00055 static bool CheckConnectChecksum(const unsigned char *data, int length); 00056 static void Xor(unsigned char *data, int length); 00057 }; 00058 00059 void cCCcamCrypt::Init(const unsigned char *key, int length, bool l) 00060 { 00061 log=l; 00062 for(int pos=0; pos<=255; pos++) keytable[pos]=pos; 00063 int result=0; 00064 unsigned char curr_char=0; 00065 for(int pos=0; pos<=255; pos++) { 00066 curr_char+=keytable[pos] + key[result]; 00067 Swap(keytable+pos,keytable+curr_char); 00068 result=(result+1)%length; 00069 } 00070 state=key[0]; counter=0; sum=0; 00071 if(log) LDUMP(L_CC_CCCAM2EX,keytable,sizeof(keytable),"cccrypt init state=%d table",state); 00072 } 00073 00074 void cCCcamCrypt::Decrypt(const unsigned char *in, unsigned char *out, int length) 00075 { 00076 for(int pos=0; pos<length; pos++) { 00077 sum+=keytable[++counter]; 00078 Swap(keytable+counter,keytable+sum); 00079 out[pos]=in[pos] ^ state ^ keytable[(keytable[sum]+keytable[counter])&0xFF]; 00080 state^=out[pos]; 00081 } 00082 if(log) LDUMP(L_CC_CCCAM2EX,keytable,sizeof(keytable),"cccrypt decrypt state=%d table",state); 00083 } 00084 00085 void cCCcamCrypt::DecryptRC4(const unsigned char *in, unsigned char *out, int length) 00086 { 00087 for(int pos=0; pos<length; pos++) { 00088 sum+=keytable[++counter]; 00089 Swap(keytable+counter,keytable+sum); 00090 out[pos]=in[pos] ^ keytable[(keytable[sum]+keytable[counter])&0xFF]; 00091 state^=out[pos]; 00092 } 00093 if(log) LDUMP(L_CC_CCCAM2EX,keytable,sizeof(keytable),"rc4crypt decrypt state=%d table",state); 00094 } 00095 00096 void cCCcamCrypt::Encrypt(const unsigned char *in, unsigned char *out, int length) 00097 { 00098 // There is a side-effect in this function: 00099 // If in & out pointer are the same, then state is xor'ed with modified input 00100 // (because output(=in ptr) is written before state xor) 00101 // This side-effect is used when initialising the encrypt state! 00102 for(int pos=0; pos<length; pos++) { 00103 sum+=keytable[++counter]; 00104 Swap(keytable+counter,keytable+sum); 00105 out[pos]=in[pos] ^ state ^ keytable[(keytable[sum]+keytable[counter])&0xFF]; 00106 state^=in[pos]; 00107 } 00108 if(log) LDUMP(L_CC_CCCAM2EX,keytable,sizeof(keytable),"cccrypt encrypt state=%d table",state); 00109 } 00110 00111 void cCCcamCrypt::Swap(unsigned char *p1, unsigned char *p2) 00112 { 00113 unsigned char tmp=*p1; *p1=*p2; *p2=tmp; 00114 } 00115 00116 void cCCcamCrypt::ScrambleDcw(unsigned char *data, const unsigned char *nodeid, unsigned int shareid) 00117 { 00118 long long n=bswap_64(*(long long *)nodeid); 00119 for(unsigned int i=0; i<16; i++) { 00120 char final=data[i]^(n&0xFF); 00121 if(i&1) final=~final; 00122 data[i]=final^(shareid&0xFF); 00123 n>>=4; shareid>>=2; 00124 } 00125 } 00126 00127 bool cCCcamCrypt::DcwChecksum(const unsigned char *data) 00128 { 00129 bool res=true; 00130 if(((data[0]+data[1]+data[2])&0xff)!=data[3] || 00131 ((data[4]+data[5]+data[6])&0xff)!=data[7]) { 00132 res=false; 00133 PRINTF(L_CC_CCCAM2EX,"warning: even CW checksum failed"); 00134 } 00135 if(((data[8]+data[9]+data[10])&0xff)!=data[11] || 00136 ((data[12]+data[13]+data[14])&0xff)!=data[15]) { 00137 res=false; 00138 PRINTF(L_CC_CCCAM2EX,"warning: odd CW checksum failed"); 00139 } 00140 return res; 00141 } 00142 00143 bool cCCcamCrypt::CheckConnectChecksum(const unsigned char *data, int length) 00144 { 00145 if(length==16) { 00146 bool valid=true; 00147 // CCcam 2.1.2 don't use connect checksum 00148 //for(int i=0; i<4; i++) 00149 // if(((data[i+0]+data[i+4]+data[i+8])&0xFF)!=data[i+12]) valid=false; 00150 return valid; 00151 } 00152 return false; 00153 } 00154 00155 void cCCcamCrypt::Xor(unsigned char *data, int length) 00156 { 00157 if(length>=16) 00158 for(int index=0; index<8; index++) { 00159 data[8]=index*data[0]; 00160 if(index<=5) data[0]^=cccamstr[index]; 00161 data++; 00162 } 00163 } 00164 00165 // -- cCmd0cCrypt -------------------------------------------------------------- 00166 00167 #define CMD0C_MODE_PLAIN 0 00168 #define CMD0C_MODE_RC6 1 00169 #define CMD0C_MODE_RC4 2 00170 #define CMD0C_MODE_CC 3 00171 #define CMD0C_MODE_AES 4 00172 #define CMD0C_MODE_IDEA 5 00173 00174 class cCmd0cCrypt { 00175 private: 00176 int mode; 00177 cAES aes; 00178 cIDEA idea; 00179 IdeaKS ks; 00180 cRC6 rc6; 00181 cCCcamCrypt cc; 00182 public: 00183 cCmd0cCrypt(void); 00184 void Reset(void); 00185 void SetMode(int m); 00186 void SetKey(const unsigned char *key, int l); 00187 void Decrypt(const unsigned char *in, int len, unsigned char *out); 00188 }; 00189 00190 cCmd0cCrypt::cCmd0cCrypt(void) 00191 { 00192 Reset(); 00193 } 00194 00195 void cCmd0cCrypt::Reset(void) 00196 { 00197 mode=CMD0C_MODE_PLAIN; 00198 PRINTF(L_CC_CCCAM2EX,"cmd 0c crypt mode now %d",mode); 00199 } 00200 00201 void cCmd0cCrypt::SetMode(int m) 00202 { 00203 mode=m; 00204 PRINTF(L_CC_CCCAM2EX,"cmd 0c crypt mode now %d",mode); 00205 } 00206 00207 void cCmd0cCrypt::SetKey(const unsigned char *key, int l) 00208 { 00209 unsigned char buff[32]; 00210 memset(buff,0,sizeof(buff)); 00211 if(l>32) l=32; 00212 memcpy(buff,key,l); 00213 switch(mode) { 00214 case CMD0C_MODE_PLAIN: 00215 break; 00216 case CMD0C_MODE_RC6: 00217 rc6.SetKey(buff,32); 00218 break; 00219 case CMD0C_MODE_RC4: 00220 case CMD0C_MODE_CC: 00221 cc.Init(buff,32,true); 00222 break; 00223 case CMD0C_MODE_AES: 00224 aes.SetKey(buff); 00225 break; 00226 case CMD0C_MODE_IDEA: 00227 idea.SetDecKey(buff,&ks); 00228 break; 00229 } 00230 } 00231 00232 void cCmd0cCrypt::Decrypt(const unsigned char *in, int len, unsigned char *out) 00233 { 00234 switch(mode) { 00235 case CMD0C_MODE_PLAIN: 00236 memcpy(out,in,len); 00237 break; 00238 case CMD0C_MODE_RC6: 00239 for(int i=0; i<(len&~15); i+=16) rc6.Decrypt(in+i,out+i); 00240 break; 00241 case CMD0C_MODE_RC4: 00242 cc.Encrypt(in,out,len); 00243 break; 00244 case CMD0C_MODE_CC: 00245 cc.Decrypt(in,out,len); 00246 break; 00247 case CMD0C_MODE_AES: 00248 aes.Decrypt(in,len,out); 00249 break; 00250 case CMD0C_MODE_IDEA: 00251 idea.EcbEncrypt(in,len,out,&ks); 00252 for(int i=8; i<len; i+=8) 00253 for(int j=0; j<8; j++) 00254 out[j+i]^=in[j+i-8]; 00255 break; 00256 } 00257 } 00258 00259 // -- cEcmShare ---------------------------------------------------------------- 00260 00261 class cEcmShares; 00262 00263 class cEcmShare : public cSimpleItem { 00264 friend class cEcmShares; 00265 private: 00266 int source, transponder, pid; 00267 int shareid; 00268 int status; 00269 public: 00270 cEcmShare(const cEcmInfo *ecm, int id); 00271 }; 00272 00273 cEcmShare::cEcmShare(const cEcmInfo *ecm, int id) 00274 { 00275 pid=ecm->ecm_pid; 00276 source=ecm->source; 00277 transponder=ecm->transponder; 00278 shareid=id; 00279 status=0; 00280 } 00281 00282 // -- cEcmShares --------------------------------------------------------------- 00283 00284 class cEcmShares : public cSimpleList<cEcmShare> { 00285 private: 00286 cEcmShare *Find(const cEcmInfo *ecm, int id); 00287 public: 00288 int FindStatus(const cEcmInfo *ecm, int id); 00289 void AddStatus(const cEcmInfo *ecm, int id, int status); 00290 }; 00291 00292 static cEcmShares ecmshares; 00293 00294 cEcmShare *cEcmShares::Find(const cEcmInfo *ecm, int id) 00295 { 00296 for(cEcmShare *e=First(); e; e=Next(e)) 00297 if(e->shareid==id && e->pid==ecm->ecm_pid && e->source==ecm->source && e->transponder==ecm->transponder) 00298 return e; 00299 return 0; 00300 } 00301 00302 int cEcmShares::FindStatus(const cEcmInfo *ecm, int id) 00303 { 00304 cEcmShare *e=Find(ecm,id); 00305 if(e) { 00306 PRINTF(L_CC_CCCAM2SH,"shareid %08x for %04x/%x/%x status %d",e->shareid,ecm->ecm_pid,ecm->source,ecm->transponder,e->status); 00307 return e->status; 00308 } 00309 return 0; 00310 } 00311 00312 void cEcmShares::AddStatus(const cEcmInfo *ecm, int id, int status) 00313 { 00314 cEcmShare *e=Find(ecm,id); 00315 const char *t="updated"; 00316 if(!e) { 00317 Add((e=new cEcmShare(ecm,id))); 00318 t="added"; 00319 } 00320 PRINTF(L_CC_CCCAM2SH,"%s shareid %08x for %04x/%x/%x status %d",t,id,ecm->ecm_pid,ecm->source,ecm->transponder,status); 00321 e->status=status; 00322 } 00323 00324 // -- cShareProv --------------------------------------------------------------- 00325 00326 class cShareProv : public cSimpleItem { 00327 public: 00328 int provid; 00329 }; 00330 00331 // -- cShare ------------------------------------------------------------------- 00332 00333 #define STDLAG 1000 00334 #define MAXLAG 5000 00335 00336 class cShares; 00337 00338 class cShare : public cSimpleItem, public cIdSet { 00339 friend class cShares; 00340 private: 00341 int shareid, caid; 00342 cSimpleList<cShareProv> prov; 00343 int hops, lag; 00344 int status; 00345 unsigned char ua[8]; 00346 bool emmready; 00347 cMsgCache *cache; 00348 // 00349 void Init(void); 00350 void SetCache(void); 00351 public: 00352 cShare(int Shareid, int Caid, int Hops, const unsigned char *Ua); 00353 cShare(const cShare *s); 00354 ~cShare(); 00355 bool UsesProv(void) const; 00356 bool HasProv(int provid) const; 00357 bool CheckAddProv(const unsigned char *prov, const unsigned char *sa); 00358 bool Compare(const cShare *s) const; 00359 int ShareID(void) const { return shareid; }; 00360 int CaID(void) const { return caid;}; 00361 int Hops(void) const { return hops; }; 00362 int Lag(void) const { return lag; }; 00363 int Status(void) const { return status; } 00364 bool EmmReady(void) const { return emmready; } 00365 cMsgCache *Cache(void) const { return cache; } 00366 }; 00367 00368 cShare::cShare(int Shareid, int Caid, int Hops, const unsigned char *Ua) 00369 { 00370 shareid=Shareid; 00371 caid=Caid; 00372 hops=Hops; 00373 lag=STDLAG; status=0; 00374 memcpy(ua,Ua,sizeof(ua)); 00375 Init(); 00376 } 00377 00378 cShare::cShare(const cShare *s) 00379 { 00380 shareid=s->shareid; 00381 caid=s->caid; 00382 hops=s->hops; 00383 lag=s->lag; 00384 status=s->status; 00385 memset(ua,0,sizeof(ua)); 00386 Init(); 00387 } 00388 00389 cShare::~cShare() 00390 { 00391 delete cache; 00392 } 00393 00394 void cShare::Init(void) 00395 { 00396 cache=0; emmready=false; 00397 if(!CheckNull(ua,sizeof(ua))) 00398 switch(caid>>8) { 00399 case 0x17: 00400 case 0x06: SetCard(new cCardIrdeto(ua[4],&ua[5])); emmready=true; break; 00401 case 0x01: SetCard(new cCardSeca(&ua[2])); emmready=true; break; 00402 case 0x0b: SetCard(new cCardConax(&ua[1])); emmready=true; break; 00403 case 0x09: SetCard(new cCardNDS(&ua[4])); emmready=true; break; 00404 case 0x05: SetCard(new cCardViaccess(&ua[3])); emmready=true; break; 00405 case 0x0d: SetCard(new cCardCryptoworks(&ua[3])); emmready=true; break; 00406 case 0x12: 00407 case 0x18: if((caid>>8)==0x18 || caid==0x1234) { 00408 SetCard(new cCardNagra2(&ua[4])); 00409 emmready=true; 00410 break; 00411 } 00412 // fall through 00413 default: PRINTF(L_CC_CCCAM2,"share %08x: can't handle unique updates for CAID %04x",shareid,caid); 00414 break; 00415 } 00416 SetCache(); 00417 } 00418 00419 void cShare::SetCache(void) 00420 { 00421 if(emmready) { 00422 if(!cache) cache=new cMsgCache(32,0); 00423 if(!cache) { 00424 emmready=false; 00425 PRINTF(L_CC_CCCAM2,"share %08x: failed to alloc EMM cache",shareid); 00426 } 00427 } 00428 else { 00429 delete cache; cache=0; 00430 } 00431 } 00432 00433 bool cShare::UsesProv(void) const 00434 { 00435 switch(caid>>8) { 00436 case 0x01: 00437 case 0x05: 00438 return true; 00439 default: 00440 return false; 00441 } 00442 } 00443 00444 bool cShare::HasProv(int provid) const 00445 { 00446 for(cShareProv *sp=prov.First(); sp; sp=prov.Next(sp)) 00447 if(sp->provid==provid) return true; 00448 return false; 00449 } 00450 00451 bool cShare::CheckAddProv(const unsigned char *pr, const unsigned char *sa) 00452 { 00453 unsigned char s[8]; 00454 memset(&s[0],0,4); memcpy(&s[4],sa,4); 00455 int provid=UINT32_BE(pr-1)&0xFFFFFF; 00456 bool res=false; 00457 if(!CheckNull(s,sizeof(s))) 00458 switch(caid>>8) { 00459 case 0x17: 00460 case 0x06: AddProv(new cProviderIrdeto(s[4],&s[5])); res=true; break; 00461 case 0x01: AddProv(new cProviderSeca(&pr[1],&s[4])); res=true; break; 00462 case 0x0b: AddProv(new cProviderConax(&s[1])); res=true; break; 00463 case 0x09: AddProv(new cProviderNDS(&s[4])); res=true; break; 00464 case 0x05: AddProv(new cProviderViaccess(&pr[0],&s[4])); res=true; break; 00465 case 0x0d: AddProv(new cProviderCryptoworks(&s[3])); res=true; break; 00466 default: PRINTF(L_CC_CCCAM2,"share %08x: can't handle shared updates for CAID %04x",shareid,caid); 00467 break; 00468 } 00469 if(res) emmready=true; 00470 SetCache(); 00471 00472 if(UsesProv() && !HasProv(provid)) { 00473 cShareProv *sp=new cShareProv; 00474 sp->provid=provid; 00475 prov.Add(sp); 00476 res=true; 00477 } 00478 return res; 00479 } 00480 00481 bool cShare::Compare(const cShare *s) const 00482 { 00483 // success or untried is better ;) 00484 if((s->status<0)!=(status<0)) return s->status>=0; 00485 // lower lag is better 00486 if(s->lag!=lag) return s->lag<lag; 00487 // lower hops is better 00488 return s->hops<hops; 00489 } 00490 00491 // -- cShares ------------------------------------------------------------------ 00492 00493 class cShares : public cRwLock, public cSimpleList<cShare> { 00494 private: 00495 cShare *Find(int shareid); 00496 public: 00497 int GetShares(const cEcmInfo *ecm, cShares *ss); 00498 void SetLag(int shareid, int lag); 00499 bool HasCaid(int caid); 00500 }; 00501 00502 cShare *cShares::Find(int shareid) 00503 { 00504 for(cShare *s=First(); s; s=Next(s)) 00505 if(s->shareid==shareid) return s; 00506 return 0; 00507 } 00508 00509 void cShares::SetLag(int shareid, int lag) 00510 { 00511 Lock(false); 00512 cShare *s=Find(shareid); 00513 if(s) { 00514 lag=min(lag,MAXLAG); 00515 if(s->lag==STDLAG) s->lag=(STDLAG+lag)/2; 00516 else s->lag=(3*s->lag+lag)/4; 00517 } 00518 Unlock(); 00519 } 00520 00521 bool cShares::HasCaid(int caid) 00522 { 00523 for(cShare *s=First(); s; s=Next(s)) 00524 if(s->CaID()==caid) return true; 00525 return false; 00526 } 00527 00528 int cShares::GetShares(const cEcmInfo *ecm, cShares *ss) 00529 { 00530 Lock(true); 00531 Clear(); 00532 ss->Lock(false); 00533 for(cShare *s=ss->First(); s; s=ss->Next(s)) { 00534 if(((s->caid==ecm->caId && (!s->UsesProv() || s->HasProv(ecm->provId))) || 00535 (s->shareid<64 && s->caid==(ecm->caId&0xFF00))) && 00536 !Find(s->shareid)) { 00537 cShare *n=new cShare(s); 00538 n->status=ecmshares.FindStatus(ecm,n->shareid); 00539 // keep the list sorted 00540 cShare *l=0; 00541 for(cShare *t=First(); t; t=Next(t)) { 00542 if(t->Compare(n)) { 00543 if(l) Add(n,l); else Ins(n); 00544 n=0; break; 00545 } 00546 l=t; 00547 } 00548 if(n) Add(n); 00549 } 00550 } 00551 ss->Unlock(); 00552 Unlock(); 00553 return Count(); 00554 } 00555 00556 // -- CCcam protocol structs --------------------------------------------------- 00557 00558 struct CmdHeader { 00559 unsigned char flags, cmd; 00560 unsigned short cmdlen; // BE 00561 } __attribute__((packed)); 00562 00563 #define SETCMDLEN(h,l) BYTE2_BE(&(h)->cmdlen,(l)-4) 00564 #define CMDLEN(h) (UINT16_BE(&(h)->cmdlen)+4) 00565 00566 struct GenericCmd { 00567 struct CmdHeader header; 00568 unsigned char payload[0]; 00569 } __attribute__((packed)); 00570 00571 struct ClientInfo { 00572 struct CmdHeader header; 00573 char username[20]; 00574 unsigned char nodeid[8]; 00575 unsigned char wantemus; 00576 char version[32], build[32]; 00577 } __attribute__((packed)); 00578 00579 struct ServerInfo { 00580 struct CmdHeader header; 00581 unsigned char nodeid[8]; 00582 char version[32], build[32]; 00583 } __attribute__((packed)); 00584 00585 struct EcmRequest { 00586 struct CmdHeader header; 00587 unsigned short caid; // BE 00588 unsigned int provid; // BE 00589 unsigned int shareid; // BE 00590 unsigned short sid; // BE 00591 unsigned char datalen; 00592 unsigned char data[0]; 00593 } __attribute__((packed)); 00594 00595 struct EmmRequest { 00596 struct CmdHeader header; 00597 unsigned short caid; // BE 00598 unsigned char dummy; //XXX what is that? 00599 unsigned int provid; // BE 00600 unsigned int shareid; // BE 00601 unsigned char datalen; 00602 unsigned char data[0]; 00603 } __attribute__((packed)); 00604 00605 struct DcwAnswer { 00606 struct CmdHeader header; 00607 unsigned char cw[16]; 00608 } __attribute__((packed)); 00609 00610 struct DelShare { 00611 struct CmdHeader header; 00612 unsigned int shareid; // BE 00613 } __attribute__((packed)); 00614 00615 struct AddShare { 00616 struct CmdHeader header; 00617 unsigned int shareid; // BE 00618 unsigned int remoteid; // BE 00619 unsigned short caid; // BE 00620 unsigned char uphops, maxdown; 00621 unsigned char cardserial[8]; 00622 } __attribute__((packed)); 00623 00624 struct ProvInfo { 00625 unsigned char count; 00626 struct { 00627 unsigned char provid[3]; 00628 unsigned char sa[4]; 00629 } prov[0]; 00630 } __attribute__((packed)); 00631 00632 struct NodeInfo { 00633 unsigned char count; 00634 unsigned char nodeid[0][8]; 00635 } __attribute__((packed)); 00636 00637 // -- cCardClientCCcam2 --------------------------------------------------------- 00638 00639 #define MAX_ECM_TIME 3000 // ms 00640 #define PING_TIME 120*1000 // ms 00641 00642 #define CMD05_MODE_UNKNOWN 0 00643 #define CMD05_MODE_PLAIN 1 00644 #define CMD05_MODE_AES 2 00645 #define CMD05_MODE_CC 3 00646 #define CMD05_MODE_RC4 4 00647 #define CMD05_MODE_LEN0 5 00648 00649 class cCardClientCCcam2 : public cCardClient , private cThread { 00650 private: 00651 cCCcamCrypt encr, decr; 00652 cShares shares; 00653 unsigned char nodeid[8]; 00654 int shareid; 00655 char username[21], password[64], versstr[32], buildstr[32]; 00656 bool login, emmProcessing, wantEmus; 00657 cTimeMs lastsend; 00658 int pendingDCW, pendingEMM, maxecmcount; 00659 // 00660 bool newcw; 00661 unsigned char cw[16]; 00662 cMutex cwmutex; 00663 cCondVar cwwait; 00664 tThreadId readerTid; 00665 // 00666 int cmd05mode, cmd05off; 00667 unsigned char cmd05aes[16], cmd0Baes[16]; 00668 cCCcamCrypt cmd05crypt; 00669 cCmd0cCrypt cmd0Ccrypt; 00670 // 00671 void PacketAnalyzer(const struct CmdHeader *hdr, int length); 00672 int CryptRecv(unsigned char *data, int len, int to=-1); 00673 bool CryptSend(const unsigned char *data, int len); 00674 protected: 00675 virtual void Logout(void); 00676 virtual void Action(void); 00677 public: 00678 cCardClientCCcam2(const char *Name); 00679 ~cCardClientCCcam2(); 00680 virtual bool Init(const char *CfgDir); 00681 virtual bool Login(void); 00682 virtual bool CanHandle(unsigned short SysId); 00683 virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw); 00684 virtual bool ProcessEMM(int caSys, const unsigned char *data); 00685 }; 00686 00687 static cCardClientLinkReg<cCardClientCCcam2> __ncd("cccam2"); 00688 00689 cCardClientCCcam2::cCardClientCCcam2(const char *Name) 00690 :cCardClient(Name) 00691 ,cThread("CCcam2 reader") 00692 { 00693 shareid=0; readerTid=0; pendingDCW=pendingEMM=maxecmcount=0; newcw=login=emmProcessing=false; 00694 cmd05mode=CMD05_MODE_UNKNOWN; cmd05off=0; 00695 so.SetRWTimeout(10*1000); 00696 } 00697 00698 cCardClientCCcam2::~cCardClientCCcam2() 00699 { 00700 Logout(); 00701 } 00702 00703 void cCardClientCCcam2::PacketAnalyzer(const struct CmdHeader *hdr, int length) 00704 { 00705 int plen=CMDLEN(hdr); 00706 if(plen<=length) { 00707 plen-=sizeof(struct CmdHeader); 00708 switch(hdr->cmd) { 00709 case 0: 00710 break; 00711 case 1: 00712 { 00713 struct DcwAnswer *dcw=(struct DcwAnswer *)hdr; 00714 if(pendingDCW>0) pendingDCW--; 00715 PRINTF(L_CC_CCCAM2,"got CW, current shareid %08x (pending %d, EMM %d, maxecmcount=%d)",shareid,pendingDCW,pendingEMM,maxecmcount); 00716 unsigned char tempcw[16], tempcw2[16]; 00717 memcpy(tempcw2,dcw->cw,16); 00718 LDUMP(L_CC_CCCAM2DT,tempcw2,16,"scrambled CW"); 00719 cCCcamCrypt::ScrambleDcw(tempcw2,nodeid,shareid); 00720 LDUMP(L_CC_CCCAM2DT,tempcw2,16,"un-scrambled CW"); 00721 cmd0Ccrypt.Decrypt(tempcw2,16,tempcw); 00722 LDUMP(L_CC_CCCAM2DT,tempcw,16, "after cmd0Ccryp"); 00723 if(cCCcamCrypt::DcwChecksum(tempcw) || pendingDCW==0) { 00724 cwmutex.Lock(); 00725 newcw=true; 00726 memcpy(cw,tempcw,16); 00727 cwwait.Broadcast(); 00728 cwmutex.Unlock(); 00729 } 00730 else PRINTF(L_CC_CCCAM2,"pending DCW, skipping bad CW"); 00731 decr.Decrypt(tempcw,tempcw,16); 00732 if(maxecmcount>0 && --maxecmcount<2) { 00733 PRINTF(L_CC_CCCAM2,"disconnecting due to key limit..."); 00734 Logout(); 00735 } 00736 break; 00737 } 00738 case 2: 00739 if(pendingEMM>0) pendingEMM--; 00740 PRINTF(L_CC_CCCAM2EX,"EMM ack (pending %d)",pendingEMM); 00741 break; 00742 case 4: 00743 { 00744 struct DelShare *del=(struct DelShare *)hdr; 00745 int shareid=UINT32_BE(&del->shareid); 00746 bool check=false; 00747 shares.Lock(true); 00748 for(cShare *s=shares.First(); s;) { 00749 cShare *n=shares.Next(s); 00750 if(s->ShareID()==shareid) { 00751 PRINTF(L_CC_CCCAM2SH,"REMOVE share %08x caid: %04x (count %d)",s->ShareID(),s->CaID(),shares.Count()); 00752 int caid=s->CaID(); 00753 if(s->EmmReady()) check=true; 00754 shares.Del(s); 00755 if(!shares.HasCaid(caid)) CaidsChanged(); 00756 } 00757 s=n; 00758 } 00759 if(check && emmProcessing) { 00760 bool emm=false; 00761 for(cShare *s=shares.First(); s; s=shares.Next(s)) 00762 if(s->EmmReady()) { emm=true; break; } 00763 if(!emm) { 00764 emmProcessing=false; 00765 PRINTF(L_CC_CCCAM2,"disabled EMM processing"); 00766 } 00767 } 00768 shares.Unlock(); 00769 break; 00770 } 00771 case 5: 00772 { 00773 PRINTF(L_CC_CCCAM2,"got cmd 05 (payload length=%d)",plen); 00774 unsigned char resp[4+256]; 00775 struct GenericCmd *gen=(struct GenericCmd *)resp; 00776 memset(resp,0,4); 00777 gen->header.cmd=5; 00778 int mode=cmd05mode; 00779 if(plen==0) mode=CMD05_MODE_LEN0; 00780 else if(plen==256) { 00781 LDUMP(L_CC_CCCAM2DT,((struct GenericCmd *)hdr)->payload,plen,"cmd 05 payload"); 00782 PRINTF(L_CC_CCCAM2EX,"cmd 05 mode %d",mode); 00783 switch(mode) { 00784 case CMD05_MODE_PLAIN: 00785 memcpy(gen->payload,((struct GenericCmd *)hdr)->payload,256); 00786 break; 00787 case CMD05_MODE_AES: 00788 { 00789 cAES aes; 00790 LDUMP(L_CC_CCCAM2EX,cmd05aes,sizeof(cmd05aes),"cmd 05 aes key"); 00791 LDUMP(L_CC_CCCAM2EX,((struct GenericCmd *)hdr)->payload,256,"cmd 05 aes in"); 00792 aes.SetKey(cmd05aes); 00793 aes.Encrypt(((struct GenericCmd *)hdr)->payload,256,gen->payload); 00794 LDUMP(L_CC_CCCAM2EX,gen->payload,256,"cmd 05 aes out"); 00795 break; 00796 } 00797 case CMD05_MODE_CC: 00798 LDUMP(L_CC_CCCAM2EX,((struct GenericCmd *)hdr)->payload,256,"cmd 05 cc in"); 00799 cmd05crypt.Encrypt(((struct GenericCmd *)hdr)->payload,gen->payload,256); 00800 LDUMP(L_CC_CCCAM2EX,gen->payload,256,"cmd 05 cc out"); 00801 break; 00802 case CMD05_MODE_RC4: 00803 LDUMP(L_CC_CCCAM2EX,((struct GenericCmd *)hdr)->payload,256,"cmd 05 rc4 in"); 00804 cmd05crypt.DecryptRC4(((struct GenericCmd *)hdr)->payload,gen->payload,256); 00805 LDUMP(L_CC_CCCAM2EX,gen->payload,256,"cmd 05 rc4 out"); 00806 break; 00807 default: 00808 mode=CMD05_MODE_UNKNOWN; 00809 break; 00810 } 00811 } 00812 else mode=CMD05_MODE_UNKNOWN; 00813 00814 if(mode==CMD05_MODE_UNKNOWN) { 00815 if(!maxecmcount) maxecmcount=50; 00816 } 00817 else maxecmcount=0; 00818 00819 int l=(mode==CMD05_MODE_UNKNOWN || mode==CMD05_MODE_LEN0) ? 4:4+256; 00820 PRINTF(L_CC_CCCAM2EX,"sending cmd 05 response (len=%d)",l); 00821 SETCMDLEN(&gen->header,l); 00822 if(!CryptSend((unsigned char *)gen,l)) 00823 PRINTF(L_CC_CCCAM2,"failed to send cmd 05 response"); 00824 break; 00825 } 00826 case 6: 00827 PRINTF(L_CC_CCCAM2,"server PONG"); 00828 break; 00829 case 7: 00830 { 00831 struct AddShare *add=(struct AddShare *)hdr; 00832 int caid=UINT16_BE(&add->caid); 00833 int shareid=UINT32_BE(&add->shareid); 00834 shares.Lock(false); 00835 if(!shares.HasCaid(caid)) CaidsChanged(); 00836 shares.Unlock(); 00837 cShare *s=new cShare(shareid,caid,add->uphops,add->cardserial); 00838 LBSTARTF(L_CC_CCCAM2SH); 00839 LBPUT("ADD share %08x hops %d maxdown %d caid %04x ua ",shareid,add->uphops,add->maxdown,caid); 00840 for(int i=0; i<8; i++) LBPUT("%02x",add->cardserial[i]); 00841 struct ProvInfo *prov=(struct ProvInfo *)(add+1); 00842 if(prov->count>0) { 00843 bool first=true; 00844 for(int i=0; i<prov->count; i++) { 00845 if(s->CheckAddProv(prov->prov[i].provid,prov->prov[i].sa)) { 00846 if(first) { LBPUT(" prov"); first=false; } 00847 LBPUT(" %06x/%08x",UINT32_BE(prov->prov[i].provid-1)&0xFFFFFF,UINT32_BE(prov->prov[i].sa)); 00848 } 00849 } 00850 } 00851 if(s->EmmReady()) LBPUT(" (EMM)"); 00852 LBEND(); 00853 shares.Lock(true); 00854 shares.Add(s); 00855 if(s->EmmReady() && !emmProcessing && emmAllowed) { 00856 emmProcessing=true; 00857 PRINTF(L_CC_CCCAM2,"enabled EMM processing"); 00858 } 00859 shares.Unlock(); 00860 break; 00861 } 00862 case 8: 00863 { 00864 struct ServerInfo *srv=(struct ServerInfo *)hdr; 00865 if(plen==0x48) { 00866 LDUMP(L_CC_LOGIN,srv->nodeid,sizeof(srv->nodeid),"%s: server version %s build %s nodeid",name,srv->version,srv->build); 00867 memcpy(cmd0Baes+0,srv->nodeid,8); 00868 memcpy(cmd0Baes+8,srv->version,8); 00869 LDUMP(L_CC_CCCAM2EX,cmd0Baes,sizeof(cmd0Baes),"cmd 0B aes key"); 00870 cmd05mode=CMD05_MODE_UNKNOWN; 00871 } 00872 else if(plen>=0x00 && plen<=0x0f) { 00873 cmd05off=plen; 00874 PRINTF(L_CC_CCCAM2EX,"cmd 05 offset now %d",cmd05off); 00875 } 00876 else if((plen>=0x10 && plen<=0x1f) || (plen>=0x24 && plen<=0x2b)) { 00877 cmd05crypt.Init(((struct GenericCmd *)hdr)->payload,plen,true); 00878 cmd05mode=CMD05_MODE_RC4; 00879 PRINTF(L_CC_CCCAM2EX,"cmd 05 mode now RC4"); 00880 LDUMP(L_CC_CCCAM2EX,((struct GenericCmd *)hdr)->payload,plen,"cmd 05 key payload"); 00881 } 00882 else if(plen==0x20) { 00883 memcpy(cmd05aes,((struct GenericCmd *)hdr)->payload+cmd05off,sizeof(cmd05aes)); 00884 cmd05mode=CMD05_MODE_AES; 00885 PRINTF(L_CC_CCCAM2EX,"cmd 05 mode now AES (offset=%d)",cmd05off); 00886 LDUMP(L_CC_CCCAM2EX,((struct GenericCmd *)hdr)->payload,plen,"cmd 05 key payload"); 00887 LDUMP(L_CC_CCCAM2EX,cmd05aes,sizeof(cmd05aes),"cmd 05 aes key"); 00888 } 00889 else if(plen==0x21) { 00890 cmd05crypt.Init(((struct GenericCmd *)hdr)->payload+cmd05off,plen,true); 00891 cmd05mode=CMD05_MODE_RC4; 00892 PRINTF(L_CC_CCCAM2EX,"cmd 05 mode now CC (offset=%d)",cmd05off); 00893 LDUMP(L_CC_CCCAM2EX,((struct GenericCmd *)hdr)->payload,plen,"cmd 05 key payload"); 00894 } 00895 else if(plen==0x22) { 00896 cmd05mode=CMD05_MODE_PLAIN; 00897 PRINTF(L_CC_CCCAM2EX,"cmd 05 mode now PLAIN"); 00898 } 00899 else if(plen==0x23) { 00900 cmd05mode=CMD05_MODE_UNKNOWN; 00901 PRINTF(L_CC_CCCAM2EX,"cmd 05 mode now UNKNOWN"); 00902 } 00903 else if(plen==0x2c) { 00904 memcpy(cmd05aes,((struct GenericCmd *)hdr)->payload+strlen(password),sizeof(cmd05aes)); 00905 cmd05mode=CMD05_MODE_AES; 00906 PRINTF(L_CC_CCCAM2EX,"cmd 05 mode now AES (offset=password=%d)",strlen(password)); 00907 LDUMP(L_CC_CCCAM2EX,((struct GenericCmd *)hdr)->payload,plen,"cmd 05 key payload"); 00908 LDUMP(L_CC_CCCAM2EX,cmd05aes,sizeof(cmd05aes),"cmd 05 aes key"); 00909 } 00910 else if(plen==0x2d) { 00911 memcpy(cmd05aes,((struct GenericCmd *)hdr)->payload+strlen(username),sizeof(cmd05aes)); 00912 cmd05mode=CMD05_MODE_AES; 00913 PRINTF(L_CC_CCCAM2EX,"cmd 05 mode now AES (offset=username=%d)",strlen(username)); 00914 LDUMP(L_CC_CCCAM2EX,((struct GenericCmd *)hdr)->payload,plen,"cmd 05 key payload"); 00915 LDUMP(L_CC_CCCAM2EX,cmd05aes,sizeof(cmd05aes),"cmd 05 aes key"); 00916 } 00917 else { 00918 PRINTF(L_CC_CCCAM2,"unknown format of serverinfo"); 00919 } 00920 break; 00921 } 00922 case 0xb: 00923 { 00924 PRINTF(L_CC_CCCAM2,"got cmd 0b (payload length=%d)",plen); 00925 unsigned char resp[4+16]; 00926 struct GenericCmd *gen=(struct GenericCmd *)resp; 00927 memset(resp,0,4); 00928 gen->header.cmd=0xb; 00929 LDUMP(L_CC_CCCAM2EX,cmd0Baes,sizeof(cmd0Baes),"cmd 0b aes key"); 00930 LDUMP(L_CC_CCCAM2EX,((struct GenericCmd *)hdr)->payload,16,"cmd 0b aes in"); 00931 cAES aes; 00932 aes.SetKey(cmd0Baes); 00933 aes.Encrypt(((struct GenericCmd *)hdr)->payload,16,gen->payload); 00934 LDUMP(L_CC_CCCAM2EX,gen->payload,16,"cmd 0b aes out"); 00935 PRINTF(L_CC_CCCAM2EX,"sending cmd 0b response"); 00936 SETCMDLEN(&gen->header,sizeof(resp)); 00937 if(!CryptSend((unsigned char *)gen,sizeof(resp))) 00938 PRINTF(L_CC_CCCAM2,"failed to send cmd 0b response"); 00939 break; 00940 } 00941 case 0xc: 00942 { 00943 PRINTF(L_CC_CCCAM2,"got cmd 0c (payload length=%d)",plen); 00944 unsigned char *out=AUTOMEM(plen); 00945 LDUMP(L_CC_CCCAM2EX,((struct GenericCmd *)hdr)->payload,plen,"cmd 0c in"); 00946 cmd0Ccrypt.Decrypt(((struct GenericCmd *)hdr)->payload,plen,out); 00947 LDUMP(L_CC_CCCAM2EX,out,plen,"cmd 0c out"); 00948 switch(out[0]) { 00949 case 0: cmd0Ccrypt.SetMode(CMD0C_MODE_RC6); break; 00950 case 1: cmd0Ccrypt.SetMode(CMD0C_MODE_RC4); break; 00951 case 2: cmd0Ccrypt.SetMode(CMD0C_MODE_CC); break; 00952 case 3: cmd0Ccrypt.SetMode(CMD0C_MODE_AES); break; 00953 case 4: cmd0Ccrypt.SetMode(CMD0C_MODE_IDEA); break; 00954 default: cmd0Ccrypt.SetMode(CMD0C_MODE_PLAIN); break; 00955 } 00956 cmd0Ccrypt.SetKey(out,plen); 00957 break; 00958 } 00959 case 0xd: 00960 { 00961 PRINTF(L_CC_CCCAM2,"got cmd 0d (payload length=%d)",plen); 00962 unsigned char *out=AUTOMEM(plen); 00963 cmd0Ccrypt.Decrypt(((struct GenericCmd *)hdr)->payload,plen,out); 00964 cmd0Ccrypt.SetKey(out,plen); 00965 break; 00966 } 00967 case 0xff: 00968 case 0xfe: 00969 if(pendingDCW>0) pendingDCW--; 00970 if(hdr->cmd==0xfe) PRINTF(L_CC_CCCAM2,"share not found on server (%d pending)",pendingDCW); 00971 else PRINTF(L_CC_CCCAM2,"server can't decode this ecm, (%d pending)",pendingDCW); 00972 cwmutex.Lock(); 00973 newcw=false; 00974 cwwait.Broadcast(); 00975 cwmutex.Unlock(); 00976 break; 00977 default: 00978 LDUMP(L_CC_CCCAM2,hdr,length,"got unhandled cmd %x:",hdr->cmd); 00979 break; 00980 } 00981 } 00982 else 00983 PRINTF(L_CC_CCCAM2,"cmdlen mismatch: cmdlen=%d length=%d",plen,length); 00984 } 00985 00986 bool cCardClientCCcam2::CanHandle(unsigned short SysId) 00987 { 00988 if(!login) return cCardClient::CanHandle(SysId); 00989 bool res=false; 00990 shares.Lock(false); 00991 for(cShare *s=shares.First(); s; s=shares.Next(s)) 00992 if(s->CaID()==SysId) { res=true; break; } 00993 shares.Unlock(); 00994 return res; 00995 } 00996 00997 bool cCardClientCCcam2::Init(const char *config) 00998 { 00999 cMutexLock lock(this); 01000 // defaults 01001 strn0cpy(versstr,"2.0.11",sizeof(versstr)); 01002 strn0cpy(buildstr,"2892",sizeof(buildstr)); 01003 for(unsigned int i=0; i<sizeof(nodeid); i++) nodeid[i]=rand(); 01004 wantEmus=false; 01005 01006 int n=0, num=0; 01007 Logout(); 01008 char params[256]; 01009 if(!ParseStdConfig(config,&num) 01010 || (n=sscanf(&config[num],":%20[^:]:%63[^:]:%255[^:]",username,password,params))<2 ) return false; 01011 PRINTF(L_CC_CORE,"%s: username=%s password=%s",name,username,password); 01012 if(n>2) { 01013 char *save; 01014 char *p=strtok_r(params,",",&save); 01015 while(p) { 01016 char *v=index(p,'='); 01017 if(v) { 01018 *v++=0; 01019 if(!strcasecmp(p,"NODEID")) { 01020 const char *v2=v; 01021 if(GetHex(v2,nodeid,sizeof(nodeid),false)!=sizeof(nodeid)) { 01022 PRINTF(L_CC_CORE,"NODEID parameter format error"); 01023 return false; 01024 } 01025 } 01026 else if(!strcasecmp(p,"VERSION")) 01027 strn0cpy(versstr,v,sizeof(versstr)); 01028 else if(!strcasecmp(p,"BUILD")) 01029 strn0cpy(buildstr,v,sizeof(buildstr)); 01030 else if(!strcasecmp(p,"WANTEMUS")) { 01031 wantEmus=(atoi(v)!=0); 01032 if(wantEmus) PRINTF(L_CC_CORE,"requesting emulations from server"); 01033 } 01034 else { 01035 PRINTF(L_CC_CORE,"unknown parameter '%s'",p); 01036 return false; 01037 } 01038 } 01039 else { 01040 PRINTF(L_CC_CORE,"bad parameter format '%s'",p); 01041 return false; 01042 } 01043 p=strtok_r(0,",",&save); 01044 } 01045 } 01046 LDUMP(L_CC_CORE,nodeid,sizeof(nodeid),"our nodeid:"); 01047 PRINTF(L_CC_CORE,"pretended CCcam version '%s' build '%s'",versstr,buildstr); 01048 return true; 01049 } 01050 01051 void cCardClientCCcam2::Logout(void) 01052 { 01053 PRINTF(L_CC_CCCAM2,"logout from server initiated"); 01054 login=false; 01055 Cancel(cThread::ThreadId()!=readerTid ? 2:-1); 01056 readerTid=0; 01057 PRINTF(L_CC_CCCAM2EX,"reader thread stopped"); 01058 cCardClient::Logout(); 01059 PRINTF(L_CC_CCCAM2EX,"network shut down"); 01060 shares.Lock(true); 01061 shares.Clear(); 01062 emmProcessing=false; 01063 shares.Unlock(); 01064 pendingDCW=pendingEMM=maxecmcount=0; 01065 cmd05mode=CMD05_MODE_UNKNOWN; cmd05off=0; 01066 cmd0Ccrypt.Reset(); 01067 PRINTF(L_CC_CCCAM2EX,"logout done"); 01068 } 01069 01070 bool cCardClientCCcam2::Login(void) 01071 { 01072 Logout(); 01073 if(!so.Connect(hostname,port)) return false; 01074 so.SetQuietLog(true); 01075 01076 unsigned char buffer[512]; 01077 int len; 01078 if((len=RecvMsg(buffer,16))<0) { 01079 PRINTF(L_CC_CCCAM2,"no welcome from server"); 01080 return false; 01081 } 01082 LDUMP(L_CC_CCCAM2DT,buffer,len,"welcome answer:"); 01083 if(!cCCcamCrypt::CheckConnectChecksum(buffer,len)) { 01084 PRINTF(L_CC_CCCAM2,"bad welcome from server"); 01085 Logout(); 01086 return false; 01087 } 01088 PRINTF(L_CC_CCCAM2EX,"welcome checksum correct"); 01089 01090 cCCcamCrypt::Xor(buffer,len); 01091 unsigned char buff2[64]; 01092 SHA1(buffer,len,buff2); 01093 decr.Init(buff2,20); 01094 decr.Decrypt(buffer,buffer,16); 01095 encr.Init(buffer,16); 01096 encr.Encrypt(buff2,buff2,20); 01097 01098 LDUMP(L_CC_CCCAM2DT,buff2,20,"welcome response:"); 01099 if(!CryptSend(buff2,20)) { 01100 PRINTF(L_CC_CCCAM2,"failed to send welcome response"); 01101 return false; 01102 } 01103 01104 memset(buffer,0,20); 01105 strcpy((char *)buffer,username); 01106 LDUMP(L_CC_CCCAM2DT,buffer,20,"send username:"); 01107 if(!CryptSend(buffer,20)) { 01108 PRINTF(L_CC_CCCAM2,"failed to send username"); 01109 return false; 01110 } 01111 01112 encr.Encrypt((unsigned char *)password,buffer,strlen(password)); 01113 if(!CryptSend((unsigned char *)cccamstr,6)) { 01114 PRINTF(L_CC_CCCAM2,"failed to send password hash"); 01115 return false; 01116 } 01117 01118 if((len=CryptRecv(buffer,20))<0) { 01119 PRINTF(L_CC_CCCAM2,"no login answer from server"); 01120 return false; 01121 } 01122 LDUMP(L_CC_CCCAM2DT,buffer,len,"login answer:"); 01123 01124 if(strcmp(cccamstr,(char *)buffer)!=0) { 01125 PRINTF(L_CC_CCCAM2,"login failed"); 01126 Logout(); 01127 return false; 01128 } 01129 PRINTF(L_CC_LOGIN,"CCcam login succeed"); 01130 01131 struct ClientInfo clt; 01132 memset(&clt,0,sizeof(clt)); 01133 clt.header.cmd=0; 01134 SETCMDLEN(&clt.header,sizeof(clt)); 01135 strcpy(clt.username,username); 01136 strn0cpy(clt.version,versstr,sizeof(clt.version)); 01137 strn0cpy(clt.build,buildstr,sizeof(clt.build)); 01138 memcpy(clt.nodeid,nodeid,8); 01139 clt.wantemus=wantEmus; 01140 LDUMP(L_CC_CCCAM2DT,&clt,sizeof(clt),"send clientinfo:"); 01141 if(!CryptSend((unsigned char*)&clt,sizeof(clt))) { 01142 PRINTF(L_CC_CCCAM2,"failed to send clientinfo"); 01143 return false; 01144 } 01145 login=true; 01146 Start(); 01147 return true; 01148 } 01149 01150 bool cCardClientCCcam2::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw) 01151 { 01152 cMutexLock lock(this); 01153 if(!so.Connected() && !Login()) { Logout(); return false; } 01154 if(!CanHandle(ecm->caId)) return false; 01155 PRINTF(L_CC_CCCAM2,"ECM caid %04x prov %04x sid %d pid %04x",ecm->caId,ecm->provId,ecm->prgId,ecm->ecm_pid); 01156 int sctlen=SCT_LEN(data); 01157 if(sctlen>=256) { 01158 PRINTF(L_CC_CCCAM2,"ECM data length >=256 not supported by CCcam"); 01159 return false; 01160 } 01161 int ecm_len=sizeof(struct EcmRequest)+sctlen; 01162 struct EcmRequest *req=(struct EcmRequest *)AUTOMEM(ecm_len); 01163 memset(req,0,sizeof(struct EcmRequest)); 01164 memcpy(req+1,data,sctlen); 01165 req->header.cmd=1; 01166 SETCMDLEN(&req->header,ecm_len); 01167 BYTE2_BE(&req->caid,ecm->caId); 01168 BYTE4_BE(&req->provid,ecm->provId); 01169 BYTE2_BE(&req->sid,ecm->prgId); 01170 req->datalen=sctlen; 01171 cShares curr; 01172 if(curr.GetShares(ecm,&shares)<1) { 01173 PRINTF(L_CC_CCCAM2,"no shares for this ECM"); 01174 return false; 01175 } 01176 if(LOG(L_CC_CCCAM2SH)) { 01177 PRINTF(L_CC_CCCAM2SH,"share try list for caid %04x prov %06x pid %04x",ecm->caId,ecm->provId,ecm->ecm_pid); 01178 for(cShare *s=curr.First(); s; s=curr.Next(s)) 01179 PRINTF(L_CC_CCCAM2SH,"shareid %08x hops %d %c lag %4d",s->ShareID(),s->Hops(),s->Status()>0?'+':(s->Status()<0?'-':' '),s->Lag()); 01180 } 01181 cTimeMs max(MAX_ECM_TIME); 01182 for(cShare *s=curr.First(); s && !max.TimedOut(); s=curr.Next(s)) { 01183 if((shareid=s->ShareID())==0) continue; 01184 BYTE4_BE(&req->shareid,shareid); 01185 PRINTF(L_CC_CCCAM2EX,"now try shareid %08x",shareid); 01186 LDUMP(L_CC_CCCAM2DT,req,ecm_len,"send ecm:"); 01187 if(pendingDCW>0) 01188 PRINTF(L_CC_CCCAM2,"WARN: there are pending %d DCW answers. This may cause trouble...",pendingDCW); 01189 pendingDCW++; 01190 if(!CryptSend((unsigned char *)req,ecm_len)) { 01191 PRINTF(L_CC_CCCAM2,"failed to send ecm request"); 01192 break; 01193 } 01194 cwmutex.Lock(); 01195 newcw=false; 01196 cTimeMs lag; 01197 if(cwwait.TimedWait(cwmutex,MAXLAG)) { 01198 uint64_t l=lag.Elapsed(); 01199 shares.SetLag(shareid,l); 01200 PRINTF(L_CC_CCCAM2EX,"wait returned after %lld",l); 01201 if(newcw) { 01202 // check for partial CW 01203 if(!CheckNull(cw+0,8)) memcpy(Cw+0,cw+0,8); 01204 if(!CheckNull(cw+8,8)) memcpy(Cw+8,cw+8,8); 01205 cwmutex.Unlock(); 01206 ecmshares.AddStatus(ecm,shareid,1); 01207 PRINTF(L_CC_CCCAM2,"got CW"); 01208 return true; 01209 } 01210 else PRINTF(L_CC_CCCAM2EX,"no CW from this share"); 01211 } 01212 else { 01213 uint64_t l=lag.Elapsed(); 01214 shares.SetLag(shareid,l); 01215 PRINTF(L_CC_CCCAM2EX,"getting CW timed out after %lld",l); 01216 } 01217 ecmshares.AddStatus(ecm,shareid,-1); 01218 cwmutex.Unlock(); 01219 } 01220 PRINTF(L_CC_ECM,"%s: unable to decode the channel",name); 01221 return false; 01222 } 01223 01224 bool cCardClientCCcam2::ProcessEMM(int caSys, const unsigned char *data) 01225 { 01226 bool res=false; 01227 if(emmProcessing && emmAllowed) { 01228 cMutexLock lock(this); 01229 shares.Lock(false); 01230 for(cShare *s=shares.First(); s; s=shares.Next(s)) { 01231 if(s->EmmReady() && s->CaID()==caSys) { 01232 cProvider *p; 01233 cAssembleData ad(data); 01234 if(s->MatchAndAssemble(&ad,0,&p)) { 01235 const unsigned char *d; 01236 while((d=ad.Assembled())) { 01237 int len=SCT_LEN(d); 01238 int id=s->Cache()->Get(d,len,0); 01239 if(id>0 || emmAllowed>1) { 01240 if(len<256) { 01241 unsigned char bb[sizeof(struct EmmRequest)+256]; 01242 struct EmmRequest *req=(struct EmmRequest *)bb; 01243 int emm_len=sizeof(struct EmmRequest)+len; 01244 memset(req,0,sizeof(struct EmmRequest)); 01245 memcpy(req+1,d,len); 01246 req->header.cmd=2; 01247 SETCMDLEN(&req->header,emm_len); 01248 BYTE2_BE(&req->caid,s->CaID()); 01249 BYTE4_BE(&req->provid,p ? p->ProvId() : 0); 01250 BYTE4_BE(&req->shareid,s->ShareID()); 01251 req->datalen=len; 01252 LDUMP(L_CC_CCCAM2DT,req,emm_len,"send emm (share %08x, caid %04x, pending %d, EMM %d):",s->ShareID(),s->CaID(),pendingDCW,pendingEMM); 01253 pendingEMM++; 01254 if(!CryptSend((unsigned char *)req,emm_len)) 01255 PRINTF(L_CC_CCCAM2,"failed to send emm request"); 01256 } 01257 else PRINTF(L_CC_CCCAM2,"EMM data length >=256 not supported by CCcam"); 01258 s->Cache()->Cache(id,true,0); 01259 } 01260 } 01261 res=true; 01262 } 01263 } 01264 } 01265 shares.Unlock(); 01266 } 01267 return res; 01268 } 01269 01270 void cCardClientCCcam2::Action(void) 01271 { 01272 readerTid=cThread::ThreadId(); 01273 int cnt=0, dec=0; 01274 while(Running() && so.Connected()) { 01275 unsigned char recvbuff[1024]; 01276 int len=sizeof(recvbuff)-cnt; 01277 if(len==0) { 01278 HEXDUMP(L_GEN_DEBUG,recvbuff,sizeof(recvbuff),"internal: cccam2 read buffer overflow"); 01279 Logout(); 01280 break; 01281 } 01282 len=RecvMsg(recvbuff+cnt,-len,200); 01283 if(len>0) { 01284 PRINTF(L_CC_CCCAM2DT,"net read: len=%d cnt=%d dec=%d",len,cnt+len,dec); 01285 cnt+=len; 01286 } 01287 // We cannot decrypt the whole buffer because it might contain an DCW 01288 // cmd followed by others. But the DCW has an additional Decrypt() during 01289 // processing, so the crypt state would be wrong for the rest of the buffer. 01290 int proc=0; 01291 while(proc+(int)sizeof(struct CmdHeader)<=cnt) { 01292 // First decrypt the cmd header only! 01293 int a; 01294 if((a=proc+sizeof(struct CmdHeader)-dec)>0) { 01295 decr.Decrypt(recvbuff+dec,recvbuff+dec,a); 01296 dec+=a; 01297 PRINTF(L_CC_CCCAM2DT,"hdr decrypt: cnt=%d proc=%d dec=%d",cnt,proc,dec); 01298 } 01299 struct CmdHeader *hdr=(struct CmdHeader *)(recvbuff+proc); 01300 int l=CMDLEN(hdr); 01301 if(l>(int)sizeof(recvbuff)) { 01302 LDUMP(L_GEN_DEBUG,recvbuff+proc,sizeof(struct CmdHeader),"internal: cccam2 cmd length exceed buffer size"); 01303 Logout(); 01304 break; 01305 } 01306 if(proc+l>cnt) { 01307 PRINTF(L_CC_CCCAM2DT,"cmd incomplete: proc+l=%d cnt=%d dec=%d",proc+l,cnt,dec); 01308 break; 01309 } 01310 // Now decrypt payload for this cmd only! 01311 if((a=proc+l-dec)>0) { 01312 decr.Decrypt(recvbuff+dec,recvbuff+dec,a); 01313 dec+=a; 01314 PRINTF(L_CC_CCCAM2DT,"payload decrypt: cnt=%d proc=%d dec=%d",cnt,proc,dec); 01315 } 01316 LDUMP(L_CC_CCCAM2DT,hdr,l,"msg in:"); 01317 PacketAnalyzer(hdr,l); 01318 proc+=l; 01319 } 01320 if(proc) { 01321 cnt-=proc; dec-=proc; 01322 memmove(recvbuff,recvbuff+proc,cnt); 01323 } 01324 if(lastsend.TimedOut()) { 01325 static const struct CmdHeader ping = { 0,6,0 }; 01326 if(!CryptSend((unsigned char *)&ping,sizeof(ping))) 01327 PRINTF(L_CC_CCCAM2,"failed to send server PING"); 01328 } 01329 usleep(10); 01330 } 01331 readerTid=0; 01332 } 01333 01334 int cCardClientCCcam2::CryptRecv(unsigned char *data, int len, int to) 01335 { 01336 int r=RecvMsg(data,len,to); 01337 if(r>0) decr.Decrypt(data,data,r); 01338 return r; 01339 } 01340 01341 bool cCardClientCCcam2::CryptSend(const unsigned char *data, int len) 01342 { 01343 unsigned char *buff=AUTOMEM(len); 01344 encr.Encrypt(data,buff,len); 01345 lastsend.Set(PING_TIME); 01346 return SendMsg(buff,len); 01347 }