|
SASC
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 <stdlib.h> 00021 #include <string.h> 00022 #include <unistd.h> 00023 00024 #include <vdr/tools.h> 00025 00026 #include <openssl/md5.h> 00027 00028 #include "system.h" 00029 #include "cam.h" 00030 #include "global.h" 00031 #include "data.h" 00032 #include "override.h" 00033 #include "opts.h" 00034 #include "log-core.h" 00035 #include "i18n.h" 00036 00037 // --- cFeature ---------------------------------------------------------------- 00038 00039 cFeature Feature; 00040 00041 bool cFeature::keyfile=false; 00042 bool cFeature::smartcard=false; 00043 00044 void cFeature::NeedsKeyFile(void) 00045 { 00046 if(!keyfile) PRINTF(L_CORE_DYN,"feature: using feature KEYFILE"); 00047 keyfile=true; 00048 } 00049 00050 void cFeature::NeedsSmartCard(void) 00051 { 00052 if(!smartcard) PRINTF(L_CORE_DYN,"feature: using feature SMARTCARD"); 00053 smartcard=true; 00054 } 00055 00056 // -- cKeySnoop ---------------------------------------------------------------- 00057 00058 cKeySnoop::cKeySnoop(cSystem *Sys, int Type, int Id, int Keynr) 00059 { 00060 ok=false; 00061 sys=Sys; type=Type; id=Id; keynr=Keynr; 00062 } 00063 00064 cKeySnoop::~cKeySnoop() 00065 { 00066 if(!ok) sys->KeyFail(type,id,keynr); 00067 } 00068 00069 void cKeySnoop::OK(cPlainKey *pk) 00070 { 00071 sys->KeyOK(pk); 00072 ok=true; 00073 } 00074 00075 // -- cLogHook ----------------------------------------------------------------- 00076 00077 cLogHook::cLogHook(int Id, const char *Name) 00078 { 00079 id=Id; name=Name; 00080 bailOut=false; 00081 } 00082 00083 // -- cSystem ------------------------------------------------------------------ 00084 00085 #define MAX_CHID 10 00086 00087 struct EcmCheck { 00088 union { 00089 struct { 00090 bool startFlag; 00091 int current, chids[MAX_CHID]; 00092 } sys06; 00093 } caid; 00094 }; 00095 00096 int cSystem::foundKeys=0; 00097 int cSystem::newKeys=0; 00098 00099 cSystem::cSystem(const char *Name, int Pri) 00100 { 00101 name=Name; pri=Pri; 00102 currentKeyStr[0]=0; doLog=true; cam=0; logecm=0; 00103 check=new struct EcmCheck; 00104 memset(check,0,sizeof(struct EcmCheck)); 00105 memset(cw,0,sizeof(cw)); 00106 // default config 00107 maxEcmTry=2; // try to get a key X times from the same ECM pid (default) 00108 hasLogger=false; 00109 needsLogger=false; 00110 local=true; 00111 needsDescrData=false; 00112 constant=false; 00113 } 00114 00115 cSystem::~cSystem() 00116 { 00117 delete check; 00118 if(logecm && cam) cam->LogEcmStatus(logecm,false); 00119 delete logecm; 00120 } 00121 00122 void cSystem::StartLog(const cEcmInfo *ecm, int caid) 00123 { 00124 if(!logecm || logecm->caId!=caid) { 00125 if(logecm && cam) cam->LogEcmStatus(logecm,false); 00126 delete logecm; 00127 logecm=new cEcmInfo(ecm); 00128 logecm->caId=caid; logecm->emmCaId=0; 00129 if(cam) cam->LogEcmStatus(logecm,true); 00130 } 00131 } 00132 00133 void cSystem::AddHook(cLogHook *hook) 00134 { 00135 if(cam) cam->AddHook(hook); 00136 } 00137 00138 bool cSystem::TriggerHook(int id) 00139 { 00140 return cam && cam->TriggerHook(id); 00141 } 00142 00143 void cSystem::CaidsChanged(void) 00144 { 00145 cGlobal::CaidsChanged(); 00146 } 00147 00148 void cSystem::ParseCADescriptor(cSimpleList<cEcmInfo> *ecms, unsigned short sysId, int source, const unsigned char *data, int len) 00149 { 00150 const int pid=WORD(data,2,0x1FFF); 00151 switch(sysId>>8) { 00152 case 0x01: // Seca style 00153 for(int p=2; p<len; p+=15) { 00154 cEcmInfo *n=new cEcmInfo(name,WORD(data,p,0x1FFF),sysId,WORD(data,p+2,0xFFFF)); 00155 if(data[p+4]==0xFF) n->SetDataIdx(p+5); 00156 ecms->Add(n); 00157 } 00158 break; 00159 case 0x05: // Viaccess style 00160 for(int p=4; p<len; p+=2+data[p+1]) 00161 if(data[p]==0x14) 00162 ecms->Add(new cEcmInfo(name,pid,sysId,(data[p+2]<<16)|(data[p+3]<<8)|(data[p+4]&0xF0))); 00163 break; 00164 default: // default style 00165 ecms->Add(new cEcmInfo(name,pid,sysId,0)); 00166 break; 00167 } 00168 } 00169 00170 void cSystem::ParseCAT(cPids *pids, const unsigned char *buffer, int source, int transponder) 00171 { 00172 if(buffer[0]==0x09) { 00173 int caid=WORD(buffer,2,0xFFFF); 00174 int pid=WORD(buffer,4,0x1FFF); 00175 if(overrides.AddEmmPids(caid,source,transponder,pids,pid)) return; 00176 switch(caid>>8) { 00177 case 0x01: // Seca style (82/84) 00178 if(buffer[1]>4) { 00179 pids->AddPid(pid,0x82,0xFF); // Unique updates 00180 for(int i=7, nn=buffer[6] ; nn ; nn--,i+=4) 00181 pids->AddPid(WORD(buffer,i,0x1FFF),0x84,0xFF); // Shared updates 00182 } 00183 break; 00184 case 0x05: // Viaccess style (88/8c/8d/8e) 00185 pids->AddPid(pid,0x88,0xF9); // mismatching 8a 00186 pids->AddPid(pid,0x8D,0xFF); 00187 break; 00188 case 0x0d: // Cryptoworks style (82/84/86/88/89) 00189 pids->AddPid(pid,0x82,0xF9); // mismatching 80 00190 pids->AddPid(pid,0x88,0xFE); 00191 break; 00192 case 0x18: // Nagra style (82/83) 00193 pids->AddPid(pid,0x82,0xFE); 00194 break; 00195 default: // default style (82) 00196 pids->AddPid(pid,0x82,0xFF); 00197 break; 00198 } 00199 } 00200 } 00201 00202 int cSystem::CheckECM(const cEcmInfo *ecm, const unsigned char *data, bool sync) 00203 { 00204 switch(ecm->caId>>8) { 00205 case 0x06: // Irdeto 00206 { 00207 const int chid=WORD(data,6,0xFFFF); 00208 // if multiple channel id's, use current one only 00209 if(sync && check->caid.sys06.current>0 && chid!=check->caid.sys06.current) { 00210 PRINTF(L_CORE_ECMPROC,"ecmcheck(%s): chid %04x != current %04x",name,chid,check->caid.sys06.current); 00211 return 3; 00212 } 00213 /* 00214 //XXX is that still needed? Seems to conflict with some Irdeto2 provider 00215 // search for fake channel id's on Stream 00216 const int cur=data[4]; 00217 const int max=data[5]; 00218 if(!sync && max>0 && max<MAX_CHID) { 00219 if(cur==0) check->caid.sys06.startFlag=true; 00220 if(check->caid.sys06.startFlag) { 00221 if(cur<=max) check->caid.sys06.chids[cur]=chid; 00222 if(cur==max) { 00223 for(int i=0 ; i<max ; i++) { 00224 if(check->caid.sys06.chids[i]==0) { 00225 check->caid.sys06.startFlag=false; 00226 PRINTF(L_CORE_ECMPROC,"ecmcheck(%s): zero chid",name); 00227 return 1; 00228 } 00229 for(int j=i+1 ; j<=max ; j++) { 00230 if(check->caid.sys06.chids[i]==check->caid.sys06.chids[j]) { 00231 check->caid.sys06.startFlag=false; 00232 PRINTF(L_CORE_ECMPROC,"ecmcheck(%s): duplicate chid %04x",name,check->caid.sys06.chids[i]); 00233 return 1; 00234 } 00235 } 00236 } 00237 } 00238 } 00239 } 00240 */ 00241 break; 00242 } 00243 } 00244 return 0; 00245 } 00246 00247 void cSystem::CheckECMResult(const cEcmInfo *ecm, const unsigned char *data, bool result) 00248 { 00249 switch(ecm->caId>>8) { 00250 case 0x06: // Irdeto 00251 check->caid.sys06.current=result ? WORD(data,6,0xFFFF) : 0; 00252 break; 00253 } 00254 } 00255 00256 void cSystem::KeyOK(cPlainKey *pk) 00257 { 00258 if(lastkey.NotLast(pk->type,pk->id,pk->keynr)) { 00259 strn0cpy(currentKeyStr,pk->ToString(false),sizeof(currentKeyStr)); 00260 PRINTF(L_CORE_ECM,"system: using key %s",*pk->ToString(true)); 00261 doLog=true; 00262 } 00263 } 00264 00265 void cSystem::KeyOK(const char *txt) 00266 { 00267 snprintf(currentKeyStr,sizeof(currentKeyStr),"%s (%s)\n",txt?txt:name,tr("undisclosed key")); 00268 doLog=true; 00269 } 00270 00271 void cSystem::KeyFail(int type, int id, int keynr) 00272 { 00273 keys.Trigger(type,id,keynr); 00274 if(lastkey.NotLast(type,id,keynr) && doLog) 00275 PRINTF(L_CORE_ECM,"system: no key found for %s",*keys.KeyString(type,id,keynr)); 00276 } 00277 00278 // -- cSystemLink -------------------------------------------------------------- 00279 00280 cSystemLink::cSystemLink(const char *Name, int Pri) 00281 { 00282 name=Name; pri=Pri; 00283 opts=0; noFF=false; 00284 cSystems::Register(this); 00285 } 00286 00287 cSystemLink::~cSystemLink() 00288 { 00289 delete opts; 00290 } 00291 00292 // -- cSystems ----------------------------------------------------------------- 00293 00294 cSystemLink *cSystems::first=0; 00295 int cSystems::nextSysIdent=0x1000; 00296 00297 void cSystems::Register(cSystemLink *sysLink) 00298 { 00299 PRINTF(L_CORE_DYN,"systems: registering CA system %s, pri %d, ident %04X",sysLink->name,sysLink->pri,nextSysIdent); 00300 sysLink->next=first; 00301 sysLink->sysIdent=nextSysIdent++; 00302 first=sysLink; 00303 } 00304 00305 int cSystems::CanHandle(int SysId, bool ff) 00306 { 00307 for(cSystemLink *sl=first; sl; sl=sl->next) 00308 if(sl->CanHandle(SysId)) 00309 return (sl->noFF && ff) ? -1:1; 00310 return 0; 00311 } 00312 00313 cSystemLink *cSystems::FindByName(const char *Name) 00314 { 00315 cSystemLink *sl=first; 00316 while(sl) { 00317 if(!strcasecmp(sl->name,Name)) return sl; 00318 sl=sl->next; 00319 } 00320 return 0; 00321 } 00322 00323 cSystemLink *cSystems::FindById(unsigned short SysId, bool ff, int oldPri) 00324 { 00325 // all pri's are negative! 00326 // oldPri = 0 -> get highest pri system 00327 // oldPri < 0 -> get highest pri system with pri<oldPri 00328 // oldPri > 0 -> get lowest pri system 00329 00330 cSystemLink *sl=first, *csl=0; 00331 while(sl) { 00332 if((!ff || !sl->noFF) && sl->CanHandle(SysId) 00333 && sl->pri<oldPri 00334 && (!csl 00335 || (oldPri<=0 && sl->pri>csl->pri) 00336 || (oldPri>0 && sl->pri<csl->pri) 00337 ) 00338 ) csl=sl; 00339 sl=sl->next; 00340 } 00341 return csl; 00342 } 00343 00344 cSystemLink *cSystems::FindByIdent(int ident) 00345 { 00346 cSystemLink *sl=first; 00347 while(sl) { 00348 if(sl->sysIdent==ident) return sl; 00349 sl=sl->next; 00350 } 00351 return 0; 00352 } 00353 00354 cSystem *cSystems::FindBySysId(unsigned short SysId, bool ff, int oldPri) 00355 { 00356 cSystemLink *csl=FindById(SysId,ff,oldPri); 00357 return csl ? csl->Create() : 0; 00358 } 00359 00360 int cSystems::FindIdentBySysId(unsigned short SysId, bool ff, int &Pri) 00361 { 00362 cSystemLink *csl=FindById(SysId,ff,Pri); 00363 if(csl) { 00364 Pri=csl->pri; 00365 return csl->sysIdent; 00366 } 00367 return 0; 00368 } 00369 00370 int cSystems::FindIdentBySysName(unsigned short SysId, bool ff, const char *Name, int &Pri) 00371 { 00372 cSystemLink *csl=FindByName(Name); 00373 if(csl && (!ff || !csl->noFF) && csl->CanHandle(SysId)) { 00374 Pri=csl->pri; 00375 return csl->sysIdent; 00376 } 00377 return 0; 00378 } 00379 00380 cSystem *cSystems::FindBySysIdent(int ident) 00381 { 00382 cSystemLink *csl=FindByIdent(ident); 00383 return csl ? csl->Create() : 0; 00384 } 00385 00386 bool cSystems::Init(const char *cfgdir) 00387 { 00388 int num=0; 00389 PRINTF(L_CORE_LOAD,"** registered systems:"); 00390 for(cSystemLink *sl=first; sl; sl=sl->next, num++) 00391 PRINTF(L_CORE_LOAD,"** %-16s (pri %3d)",sl->name,sl->pri); 00392 if(num<1) 00393 PRINTF(L_GEN_WARN,"No registered systems! Won't decode anything! Where are your libs?"); 00394 for(cSystemLink *sl=first; sl; sl=sl->next) 00395 if(!sl->Init(cfgdir)) return false; 00396 return true; 00397 } 00398 00399 void cSystems::Clean(void) 00400 { 00401 for(cSystemLink *sl=first; sl; sl=sl->next) sl->Clean(); 00402 } 00403 00404 bool cSystems::ConfigParse(const char *Name, const char *Value) 00405 { 00406 char sysName[32]; 00407 unsigned int i; 00408 for(i=0; Name[i] && Name[i]!='.' && i<sizeof(sysName); i++) 00409 sysName[i]=Name[i]; 00410 if(Name[i]) { 00411 sysName[i]=0; i++; 00412 cSystemLink *sl=FindByName(sysName); 00413 if(sl && sl->opts) return sl->opts->Parse(&Name[i],Value); 00414 } 00415 return false; 00416 } 00417 00418 void cSystems::ConfigStore(bool AsIs) 00419 { 00420 for(cSystemLink *sl=first; sl; sl=sl->next) 00421 if(sl->opts && sl->opts->Store(AsIs)) sl->NewConfig(); 00422 } 00423 00424 cOpts *cSystems::GetSystemOpts(bool start) 00425 { 00426 static cSystemLink *sl=0; 00427 sl=(start || !sl) ? first : sl->next; 00428 while(sl) { 00429 if(sl->opts) return sl->opts; 00430 sl=sl->next; 00431 } 00432 return 0; 00433 } 00434 00435 // -- cMsgCache ---------------------------------------------------------------- 00436 00437 #define FREE 0x00 // modes 00438 #define FAIL1 0x01 00439 #define FAIL2 0x3D 00440 #define FAILN 0x3E 00441 #define GOOD 0x3F 00442 #define MASK 0x3F 00443 #define QUEUED 0x40 00444 #define WAIT 0x80 00445 00446 struct Cache { 00447 int crc; 00448 int mode; 00449 }; 00450 00451 cMsgCache::cMsgCache(int NumCache, int StoreSize) 00452 { 00453 numCache=NumCache; 00454 storeSize=StoreSize; 00455 ptr=0; stores=0; maxFail=2; 00456 caches=MALLOC(struct Cache,numCache); 00457 if(caches) { 00458 Clear(); 00459 if(storeSize>0) { 00460 stores=MALLOC(unsigned char,numCache*storeSize); 00461 if(!stores) PRINTF(L_GEN_ERROR,"msgcache: no memory for store area"); 00462 } 00463 } 00464 else PRINTF(L_GEN_ERROR,"msgcache: no memory for cache"); 00465 } 00466 00467 cMsgCache::~cMsgCache() 00468 { 00469 free(caches); 00470 free(stores); 00471 } 00472 00473 void cMsgCache::SetMaxFail(int maxfail) 00474 { 00475 maxFail=min(maxfail,FAILN); 00476 PRINTF(L_CORE_MSGCACHE,"%d/%p: maxFail set to %d",getpid(),this,maxFail); 00477 } 00478 00479 void cMsgCache::Clear(void) 00480 { 00481 cMutexLock lock(&mutex); 00482 memset(caches,0,sizeof(struct Cache)*numCache); 00483 ptr=0; 00484 PRINTF(L_CORE_MSGCACHE,"%d/%p: clear",getpid(),this); 00485 } 00486 00487 struct Cache *cMsgCache::FindMsg(int crc) 00488 { 00489 int i=ptr; 00490 while(1) { 00491 if(--i<0) i=numCache-1; 00492 struct Cache * const s=&caches[i]; 00493 if(!s->mode) break; 00494 if(s->crc==crc) return s; 00495 if(i==ptr) break; 00496 } 00497 return 0; 00498 } 00499 00500 // returns: 00501 // -1 - msg cached as failed (max failed) 00502 // 0 - msg cached as good, result stored 00503 // >0 - msg not cached, queue id 00504 int cMsgCache::Get(const unsigned char *msg, int len, unsigned char *store) 00505 { 00506 unsigned char md[16]; 00507 int crc=crc32_le(0,MD5(msg,len,md),16); 00508 cMutexLock lock(&mutex); 00509 if(!caches || (storeSize>0 && !stores)) return -1; // sanity 00510 struct Cache *s; 00511 while((s=FindMsg(crc))) { 00512 if(!(s->mode&QUEUED)) break; 00513 s->mode|=WAIT; 00514 PRINTF(L_CORE_MSGCACHE,"%d/%p: msg already queued. waiting to complete",getpid(),this); 00515 wait.Wait(mutex); 00516 } 00517 int id; 00518 if(!s) { 00519 while(1) { 00520 s=&caches[ptr]; 00521 if(!(s->mode&QUEUED)) break; 00522 s->mode|=WAIT; 00523 PRINTF(L_CORE_MSGCACHE,"%d/%p: queue overwrite protection id=%d",getpid(),this,ptr+1); 00524 wait.Wait(mutex); // don't overwrite queued msg's 00525 } 00526 id=ptr+1; 00527 s->crc=crc; 00528 s->mode=QUEUED; 00529 PRINTF(L_CORE_MSGCACHE,"%d/%p: queued msg with id=%d",getpid(),this,id); 00530 ptr++; if(ptr>=numCache) { ptr=0; PRINTF(L_CORE_MSGCACHE,"msgcache: roll-over (%d)",numCache); } 00531 return id; 00532 } 00533 else { 00534 id=(s-&caches[0])+1; 00535 if(s->mode==GOOD) { 00536 if(store && storeSize>0) 00537 memcpy(store,&stores[(id-1)*storeSize],storeSize); 00538 PRINTF(L_CORE_MSGCACHE,"%d/%p: msg is cached as GOOD (%d)",getpid(),this,id); 00539 return 0; 00540 } 00541 else if(s->mode>=FAIL1 && s->mode<=FAIL2) { 00542 PRINTF(L_CORE_MSGCACHE,"%d/%p: msg is cached as FAIL%d (%d)",getpid(),this,s->mode,id); 00543 s->mode|=QUEUED; 00544 return id; 00545 } 00546 else { 00547 PRINTF(L_CORE_MSGCACHE,"%d/%p: msg is cached as FAILN (%d)",getpid(),this,id); 00548 return -1; 00549 } 00550 } 00551 } 00552 00553 int cMsgCache::Cache(int id, bool result, const unsigned char *store) 00554 { 00555 cMutexLock lock(&mutex); 00556 if(id<1 || !caches || (storeSize>0 && !stores)) return 0; // sanity 00557 struct Cache *s=&caches[id-1]; 00558 LBSTARTF(L_CORE_MSGCACHE); 00559 LBPUT("%d/%p: de-queued msg with id=%d ",getpid(),this,id); 00560 if(s->mode&WAIT) wait.Broadcast(); 00561 if(result) { 00562 if(store && storeSize>0) 00563 memcpy(&stores[(id-1)*storeSize],store,storeSize); 00564 s->mode=GOOD; 00565 LBPUT("(GOOD)"); 00566 return 0; 00567 } 00568 else { 00569 int m=s->mode&MASK; 00570 if(m==GOOD) 00571 m=s->mode=FREE; 00572 if(m==FREE || (m>=FAIL1 && m<=FAIL2)) { 00573 s->mode=(s->mode&MASK)+1; 00574 if(s->mode<maxFail) 00575 LBPUT("(FAIL%d)",s->mode); 00576 else 00577 m=s->mode=FAILN; 00578 } 00579 if(m==FAILN) 00580 LBPUT("(FAILN)"); 00581 return s->mode; 00582 } 00583 LBEND(); 00584 }