SASC
DVBSoftCAM

cccam2.c

Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines