|
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 #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 }