SASC
DVBSoftCAM

radegast.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 #include <stdio.h>
00021 #include <string.h>
00022 
00023 #include "cc.h"
00024 #include "parse.h"
00025 #include "version.h"
00026 
00027 // -- cCardClientRadegast ------------------------------------------------------
00028 
00029 #define MAXCAIDS 16
00030 
00031 class cCardClientRadegast : public cCardClient, private cIdSet {
00032 private:
00033   bool emmProcessing;
00034   int caids[MAXCAIDS], numCaids;
00035   //
00036   void InitVars(void);
00037   void SetLength(unsigned char *buff, int len);
00038   int GetLength(const unsigned char *buff);
00039   int GetNanoStart(const unsigned char *buff);
00040   int GetMsgLength(const unsigned char *buff);
00041   int GetMaxLength(const unsigned char *buff);
00042   void StartMsg(unsigned char *buff, int cmd);
00043   bool CheckLength(const unsigned char *buff, int len);
00044   void AddNano(unsigned char *buff, int nano, int len, int value);
00045   void AddNano(unsigned char *buff, int nano, int len, const unsigned char *data);
00046   bool Send(const unsigned char *buff);
00047   int Recv(unsigned char *buff, int len);
00048 public:
00049   cCardClientRadegast(const char *Name);
00050   virtual bool Init(const char *config);
00051   virtual bool Login(void);
00052   virtual bool CanHandle(unsigned short SysId);
00053   virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw);
00054   virtual bool ProcessEMM(int caSys, const unsigned char *data);
00055   };
00056 
00057 static cCardClientLinkReg<cCardClientRadegast> __rdg("Radegast");
00058 
00059 cCardClientRadegast::cCardClientRadegast(const char *Name)
00060 :cCardClient(Name)
00061 {
00062   InitVars();
00063   so.SetRWTimeout(7*1000);
00064 }
00065 
00066 void cCardClientRadegast::InitVars(void)
00067 {
00068   emmProcessing=false; numCaids=0;
00069 }
00070 
00071 bool cCardClientRadegast::CanHandle(unsigned short SysId)
00072 {
00073   cMutexLock lock(this);
00074   if(numCaids<=0) return cCardClient::CanHandle(SysId);
00075   for(int i=0; i<numCaids; i++) if(caids[i]==SysId) return true;
00076   return false;
00077 }
00078 
00079 bool cCardClientRadegast::Init(const char *config)
00080 {
00081   cMutexLock lock(this);
00082   Logout();
00083   return ParseStdConfig(config);
00084 }
00085 
00086 void cCardClientRadegast::SetLength(unsigned char *buff, int len)
00087 {
00088   if(buff[0]<=0x90) buff[1]=min(255,len);
00089   else { buff[1]=len>>8; buff[2]=len&0xFF; }
00090 }
00091 
00092 int cCardClientRadegast::GetLength(const unsigned char *buff)
00093 {
00094   return (buff[0]<=0x90) ? buff[1] : ((buff[1]<<8)+buff[2]);
00095 }
00096 
00097 int cCardClientRadegast::GetNanoStart(const unsigned char *buff)
00098 {
00099   return (buff[0]<=0x90) ? 2 : 3;
00100 }
00101 
00102 int cCardClientRadegast::GetMsgLength(const unsigned char *buff)
00103 {
00104   return GetLength(buff)+GetNanoStart(buff);
00105 }
00106 
00107 int cCardClientRadegast::GetMaxLength(const unsigned char *buff)
00108 {
00109   return (buff[0]<=0x90) ? 0xFF : 0xFFFF;
00110 }
00111 
00112 void cCardClientRadegast::StartMsg(unsigned char *buff, int cmd)
00113 {
00114   buff[0]=cmd;
00115   SetLength(buff,0);
00116 }
00117 
00118 bool cCardClientRadegast::CheckLength(const unsigned char *buff, int len)
00119 {
00120   int l=GetLength(buff)+len+2;
00121   int max=GetMaxLength(buff);
00122   if(len>255) PRINTF(L_CC_RDGD,"cmd %02x: nano too long %d > 255",buff[0],len);
00123   else if(l>max) PRINTF(L_CC_RDGD,"cmd %02x: msg too long %d > %d",buff[0],l,max);
00124   return l<=max;
00125 }
00126 
00127 void cCardClientRadegast::AddNano(unsigned char *buff, int nano, int len, int value)
00128 {
00129   unsigned char hex[4];
00130   for(int i=0; i<len; i++) hex[i]=value >> ((len-i-1)*8);
00131   AddNano(buff,nano,len,hex);
00132 }
00133 
00134 void cCardClientRadegast::AddNano(unsigned char *buff, int nano, int len, const unsigned char *data)
00135 {
00136   int pos=GetLength(buff), off=GetNanoStart(buff);
00137   if(pos<GetMaxLength(buff)) {
00138     buff[off+pos]=nano;
00139     buff[off+pos+1]=len;
00140     memcpy(&buff[off+pos+2],data,len);
00141     pos+=len+2;
00142     }
00143   SetLength(buff,pos);
00144 }
00145 
00146 bool cCardClientRadegast::Send(const unsigned char *buff)
00147 {
00148   return SendMsg(buff,GetMsgLength(buff));
00149 }
00150 
00151 int cCardClientRadegast::Recv(unsigned char *buff, int len)
00152 {
00153   if(RecvMsg(buff,1)<0) {
00154     PRINTF(L_CC_RDGD,"short read");
00155     return -1;
00156     }
00157   int n=GetNanoStart(buff);
00158   if(RecvMsg(buff+1,n-1,200)<0) {
00159     PRINTF(L_CC_RDGD,"short read(2)");
00160     return -1;
00161     }
00162   int k=GetMsgLength(buff);
00163   if(RecvMsg(buff+n,k-n,200)<0) {
00164     PRINTF(L_CC_RDGD,"short read(3)");
00165     return -1;
00166     }
00167   return k;
00168 }
00169 
00170 bool cCardClientRadegast::Login(void)
00171 {
00172   Logout();
00173   if(!so.Connect(hostname,port)) return false;
00174   PRINTF(L_CC_LOGIN,"%s: connected to %s:%d",name,hostname,port);
00175 
00176   InitVars();
00177   unsigned char buff[512];
00178   char hello[32];
00179   snprintf(hello,sizeof(hello),"rdgd/vdr-sc-%s",ScVersion);
00180   StartMsg(buff,0x90);                  // RDGD_MSG_CLIENT_HELLO
00181   AddNano(buff,1,strlen(hello),(unsigned char *)hello); // RDGD_NANO_DESCR
00182   if(!Send(buff) || Recv(buff,sizeof(buff))<0) return false;
00183   if(buff[0]==0x91) {
00184     PRINTF(L_CC_RDGD,"got server hello, assuming V4 mode");
00185     StartMsg(buff,0x94);                // RDGD_MSG_CLIENT_CAP_REQ;
00186     int n;
00187     if(!Send(buff) || (n=Recv(buff,sizeof(buff)))<0) return false;
00188     if(buff[0]==0x95) {
00189       LBSTARTF(L_CC_LOGIN);
00190       LBPUT("radegast: got caps");
00191       int caid;
00192       for(int l=GetNanoStart(buff); l<n; l+=buff[l+1]+2) {
00193         switch(buff[l]) {
00194           case 0xE2:
00195             LBPUT(" VERS %s",(char *)&buff[l+2]);
00196             break;
00197           case 0xE4: // CAP_NANO_CAID
00198             if(numCaids>=MAXCAIDS) { l=n; break; } //stop processing
00199             caid=(buff[l+2]<<8)+buff[l+3];
00200             LBPUT(" CAID %04X",caid);
00201             caids[numCaids++]=caid;
00202             // XXX we should have EMM processing setup here, but as we don't
00203             // XXX get any ua/sa we cannot filter EMM anyways
00204             break;
00205           case 0xE5: // CAP_NANO_PROVID
00206             for(int i=0; i<buff[l+1]; i+=3)
00207               LBPUT("/%02X%02X%02X",buff[l+2+i],buff[l+2+i+1],buff[l+2+i+2]);
00208             break;
00209           }
00210         }
00211       LBEND();
00212       }
00213     }
00214   else PRINTF(L_CC_RDGD,"no server hello, assuming old mode");
00215   if(emmProcessing && !emmAllowed) 
00216     PRINTF(L_CC_EMM,"%s: EMM disabled from config",name);
00217   CaidsChanged();
00218   return true;
00219 }
00220 
00221 bool cCardClientRadegast::ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw)
00222 {
00223   cMutexLock lock(this);
00224   if((!so.Connected() && !Login()) || !CanHandle(ecm->caId)) return false;
00225   so.Flush();
00226   int len=SCT_LEN(source);
00227   int keynr=-1;
00228   switch(ecm->caId>>8) {
00229     case 0x01: // Seca
00230       keynr=cParseSeca::KeyNr(source)&0x0F; break;
00231     case 0x05: // Viaccess
00232       keynr=cParseViaccess::KeyNr(source); break;
00233     case 0x18: // Nagra2
00234       if(ecm->caId>=0x1801) keynr=(source[7]&0x10) | 0x86;
00235       break;
00236     }
00237   unsigned char buff[512], tmp[10];
00238   StartMsg(buff,1);                     // CMD_ECM_KEY_ASK
00239   AddNano(buff,2,1,ecm->caId>>8);       // ECM_NANO_CAID_INDEX (old)
00240   AddNano(buff,10,2,ecm->caId);         // ECM_NANO_CAID
00241   sprintf((char *)tmp,"%08X",ecm->provId);
00242   AddNano(buff,6,8,tmp);                // ECM_NANO_PROVIDER
00243   if(keynr>=0) {
00244     sprintf((char *)tmp,"%04X",keynr);
00245     AddNano(buff,7,4,tmp);              // ECM_NANO_KEYNO
00246     }
00247   if(!CheckLength(buff,len)) return false;
00248   AddNano(buff,3,len,source);           // ECM_NANO_PACKET
00249 
00250   if(!Send(buff) || (len=Recv(buff,sizeof(buff)))<0) return false;
00251   if(buff[0]==2) {
00252     for(int l=GetNanoStart(buff); l<len; l+=buff[l+1]+2) {
00253       switch(buff[l]) {
00254         case 0x05:
00255           if(buff[l+1]==16) {
00256             // check for zero cw, as someone may not send both cw's every time
00257             if(!CheckNull(buff+l+ 2,8)) memcpy(cw+0,buff+l+ 2,8);
00258             if(!CheckNull(buff+l+10,8)) memcpy(cw+8,buff+l+10,8);
00259             return true;
00260             }
00261           else PRINTF(L_CC_RDGD,"wrong cw length %d from server",buff[l+1]);
00262           break;
00263         case 0x04:
00264           PRINTF(L_CC_ECM,"%s: key not available from server",name);
00265           break;
00266         default:
00267           PRINTF(L_CC_RDGD,"unknown nano %02x in ECM response",buff[l]);
00268           break;
00269         }
00270       }
00271     }
00272   else PRINTF(L_CC_RDGD,"bad ECM response from server %02x != 02",buff[0]);
00273   return false;
00274 }
00275 
00276 bool cCardClientRadegast::ProcessEMM(int caSys, const unsigned char *data)
00277 {
00278   if(emmProcessing && emmAllowed) {
00279     cMutexLock lock(this);
00280     int upd;
00281     cProvider *p;
00282     cAssembleData ad(data);
00283     if(MatchAndAssemble(&ad,&upd,&p)) {
00284       while((data=ad.Assembled())) {
00285         int len=SCT_LEN(data);
00286         int id=msEMM.Get(data,len,0);
00287         if(id>0 || emmAllowed>1) {
00288           unsigned char buff[512];
00289           StartMsg(buff,0x41);                  //
00290           AddNano(buff,0x42,2,caSys);           // EMM_CAID
00291           if(p) {
00292             unsigned char tmp[10];
00293             sprintf((char *)tmp,"%08X",(int)p->ProvId());
00294             AddNano(buff,0x46,8,tmp);           // EMM_PROVID
00295             }
00296 /*
00297           if(upd==2 || upd==3) {
00298             AddNano(buff,0x44,2,(unsigned char *)"aa"); // EMM_ADDR_VAL
00299             }
00300 */
00301           AddNano(buff,0x45,1,upd==3 ? 0x11 : (upd==2 ? 0x12 : 0x13)); // EMM_ADDR_TYPE
00302           if(CheckLength(buff,len)) {
00303             AddNano(buff,0x43,len,data);        // EMM_CA_DATA
00304             Send(buff);
00305             }
00306           msEMM.Cache(id,true,0);
00307           }
00308         }
00309       return true;
00310       }
00311     }
00312   return false;
00313 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines