int32_t ICC_Async_Receive (struct s_reader *reader, uint32_t size, BYTE * data) { if (reader->crdr.active==1) { call(reader->crdr.receive(reader, data, size)); if (reader->convention == ATR_CONVENTION_INVERSE && reader->crdr.need_inverse==1) ICC_Async_InvertBuffer (size, data); cs_ddump_mask(D_IFD, data, size, "IFD Received: "); return OK; } switch(reader->typ) { case R_MP35: case R_DB2COM1: case R_DB2COM2: case R_SC8in1: case R_MOUSE: call (Phoenix_Receive (reader, data, size, reader->read_timeout)); break; #if defined(LIBUSB) case R_SMART: call (SR_Receive(reader, data, size)); break; #endif case R_INTERNAL: #if defined(COOL) call (Cool_Receive(data, size)); #elif defined(AZBOX) call (Azbox_Receive(reader, data, size)); #elif defined(SCI_DEV) call (Phoenix_Receive (reader, data, size, reader->read_timeout)); #elif defined(WITH_STAPI) call (STReader_Receive(reader->stsmart_handle, data, size)); #endif break; default: cs_log("ERROR ICC_Async_Receive: unknow reader type %i",reader->typ); return ERROR; } if (reader->convention == ATR_CONVENTION_INVERSE && reader->typ <= R_MOUSE) ICC_Async_InvertBuffer (size, data); cs_ddump_mask(D_IFD, data, size, "IFD Received: "); return OK; }
int32_t Cool_Transmit (BYTE * sent, uint32_t size) { specdev()->cardbuflen = 256;//it needs to know max buffer size to respond? call (cnxt_smc_read_write(specdev()->handle, FALSE, sent, size, specdev()->cardbuffer, &specdev()->cardbuflen, 50, 0)); //call (cnxt_smc_read_write(specdev()->handle, FALSE, sent, size, specdev()->cardbuffer, &specdev()->cardbuflen, read_timeout, 0)); cs_ddump_mask(D_DEVICE, sent, size, "COOL IO: Transmit: "); return OK; }
int32_t ICC_Async_CardWrite (struct s_reader *reader, unsigned char *command, uint16_t command_len, unsigned char *rsp, uint16_t *lr) { #ifdef HAVE_PCSC if (reader->typ == R_PCSC) return (pcsc_reader_do_api(reader, command, rsp, lr, command_len)); #endif *lr = 0; //will be returned in case of error int32_t ret; LOCK_SC8IN1; int32_t try = 1; do { switch (reader->protocol_type) { if (try > 1) cs_log("Warning: reader %s needed try nr %i, next ECM has some delay:", reader->label, try); case ATR_PROTOCOL_TYPE_T0: ret = Protocol_T0_Command (reader, command, command_len, rsp, lr); break; case ATR_PROTOCOL_TYPE_T1: ret = Protocol_T1_Command (reader, command, command_len, rsp, lr); if (ret != OK) { //try to resync unsigned char resync[] = { 0x21, 0xC0, 0x00, 0xE1 }; Protocol_T1_Command (reader, resync, sizeof(resync), rsp, lr); reader->ifsc = DEFAULT_IFSC; } break; case ATR_PROTOCOL_TYPE_T14: ret = Protocol_T14_ExchangeTPDU (reader, command, command_len, rsp, lr); break; default: cs_log("Error, unknown protocol type %i",reader->protocol_type); ret = ERROR; } try++; } while ((try < 3) && (ret != OK)); //always do one retry when failing UNLOCK_SC8IN1; if (ret) { cs_debug_mask(D_TRACE, "ERROR, function call Protocol_T0_Command returns error."); return ERROR; } cs_ddump_mask(D_READER, rsp, *lr, "answer from cardreader %s:", reader->label); return OK; } int32_t ICC_Async_SetTimings (struct s_reader * reader, uint32_t wait_etu) { reader->read_timeout = ETU_to_ms(reader, wait_etu); cs_debug_mask(D_IFD, "Setting timeout to %i", wait_etu); return OK; }
int32_t Cool_Transmit (struct s_reader *reader, BYTE * sent, uint32_t size) { specdev()->cardbuflen = 256;//it needs to know max buffer size to respond? int32_t ret = cnxt_smc_read_write(specdev()->handle, FALSE, sent, size, specdev()->cardbuffer, &specdev()->cardbuflen, specdev()->read_write_transmit_timeout, 0); check_error("cnxt_smc_read_write", ret); cs_ddump_mask(D_DEVICE, sent, size, "COOL IO: Transmit: "); return OK; }
int32_t Cool_Receive (struct s_reader *reader, BYTE * data, uint32_t size) { if (size > specdev()->cardbuflen) size = specdev()->cardbuflen; //never read past end of buffer memcpy(data, specdev()->cardbuffer, size); specdev()->cardbuflen -= size; memmove(specdev()->cardbuffer, specdev()->cardbuffer+size, specdev()->cardbuflen); cs_ddump_mask(D_DEVICE, data, size, "COOL IO: Receive: "); return OK; }
static int32_t camd33_send(uchar *buf, int32_t ml) { int32_t l; if (!cur_client()->pfd) return(-1); l=boundary(4, ml); memset(buf+ml, 0, l-ml); cs_ddump_mask(D_CLIENT, buf, l, "send %d bytes to client", l); if (cur_client()->crypted) aes_encrypt(buf, l); return(send(cur_client()->pfd, buf, l, 0)); }
static int32_t camd33_recv(struct s_client * client, uchar *buf, int32_t l) { int32_t n; if (!client->pfd) return(-1); if ((n=recv(client->pfd, buf, l, 0))>0) { client->last=time((time_t *) 0); if (client->crypted) aes_decrypt(buf, n); } cs_ddump_mask(D_CLIENT, buf, n, "received %d bytes from client", n); return(n); }
void cardreader_process_ecm(struct s_reader *reader, struct s_client *cl, ECM_REQUEST *er) { if (ecm_ratelimit_check(reader, er, 1) != OK) { rdr_debug_mask(reader, D_READER, "%s: ratelimit check failed.", __func__); return; // reader_mode = 1: checkout ratelimiter in reader mode so srvid can be replaced } cs_ddump_mask(D_ATR, er->ecm, er->ecmlen, "ecm:"); struct timeb tps, tpe; cs_ftime(&tps); struct s_ecm_answer ea; memset(&ea, 0, sizeof(struct s_ecm_answer)); int32_t rc = cardreader_do_ecm(reader, er, &ea); rdr_debug_mask(reader, D_READER, "%s: cardreader_do_ecm returned rc=%d (ERROR=%d)", __func__, rc, ERROR); ea.rc = E_FOUND; //default assume found ea.rcEx = 0; //no special flag if (rc == ERROR) { char buf[32]; rdr_debug_mask(reader, D_READER, "Error processing ecm for caid %04X, srvid %04X, servicename: %s", er->caid, er->srvid, get_servicename(cl, er->srvid, er->caid, buf)); ea.rc = E_NOTFOUND; ea.rcEx = 0; ICC_Async_DisplayMsg(reader, "Eer"); } if (rc == E_CORRUPT) { char buf[32]; rdr_debug_mask(reader, D_READER, "Error processing ecm for caid %04X, srvid %04X, servicename: %s", er->caid, er->srvid, get_servicename(cl, er->srvid, er->caid, buf)); ea.rc = E_NOTFOUND; ea.rcEx = E2_WRONG_CHKSUM; //flag it as wrong checksum memcpy (ea.msglog,"Invalid ecm type for card",25); } cs_ftime(&tpe); cl->lastecm=time((time_t*)0); char ecmd5[17*3]; cs_hexdump(0, er->ecmd5, 16, ecmd5, sizeof(ecmd5)); rdr_debug_mask(reader, D_READER, "ecm hash: %s real time: %ld ms", ecmd5, 1000 * (tpe.time - tps.time) + tpe.millitm - tps.millitm); write_ecm_answer(reader, er, ea.rc, ea.rcEx, ea.cw, ea.msglog); reader_post_process(reader); }
static int32_t radegast_send_ecm(struct s_client *client, ECM_REQUEST *er, uchar *UNUSED(buf)) { int32_t n; uchar provid_buf[8]; uchar header[22] = "\x02\x01\x00\x06\x08\x30\x30\x30\x30\x30\x30\x30\x30\x07\x04\x30\x30\x30\x38\x08\x01\x02"; uchar *ecmbuf; if(!radegast_connect()) { return (-1); } if(!cs_malloc(&ecmbuf, er->ecmlen + 30)) { return -1; } ecmbuf[0] = 1; ecmbuf[1] = (er->ecmlen + 30 - 2) & 0xff; memcpy(ecmbuf + 2, header, sizeof(header)); for(n = 0; n < 4; n++) { snprintf((char *)provid_buf + (n * 2), sizeof(provid_buf) - (n * 2), "%02X", ((uchar *)(&er->prid))[4 - 1 - n]); } ecmbuf[7] = provid_buf[0]; ecmbuf[8] = provid_buf[1]; ecmbuf[9] = provid_buf[2]; ecmbuf[10] = provid_buf[3]; ecmbuf[11] = provid_buf[4]; ecmbuf[12] = provid_buf[5]; ecmbuf[13] = provid_buf[6]; ecmbuf[14] = provid_buf[7]; ecmbuf[2 + sizeof(header)] = 0xa; ecmbuf[3 + sizeof(header)] = 2; ecmbuf[4 + sizeof(header)] = er->caid >> 8; ecmbuf[5 + sizeof(header)] = er->caid & 0xff; ecmbuf[6 + sizeof(header)] = 3; ecmbuf[7 + sizeof(header)] = er->ecmlen & 0xff; memcpy(ecmbuf + 8 + sizeof(header), er->ecm, er->ecmlen); ecmbuf[4] = er->caid >> 8; client->reader->msg_idx = er->idx; n = send(client->pfd, ecmbuf, er->ecmlen + 30, 0); cs_debug_mask(D_TRACE, "radegast: sending ecm"); cs_ddump_mask(D_CLIENT, ecmbuf, er->ecmlen + 30, "ecm:"); NULLFREE(ecmbuf); return ((n < 1) ? (-1) : 0); }
static int32_t get_request(uchar *buf) { int32_t n, rc=0; if ((n=process_input(buf, 2, cfg.cmaxidle))==2) { if ((n=process_input(buf+2, buf[1], 0))>=0) n+=2; if (n-2==buf[1]) rc=n; else cs_log("WARNING: protocol error (garbage)"); } if (n>0) { cs_ddump_mask(D_CLIENT, buf, n, "received %d bytes from client", n); } return(rc); }
static int32_t oscam_ser_send(struct s_client *client, const uchar * const buf, int32_t l) { int32_t n; struct s_serial_client *serialdata=client->serialdata ; if (!client->pfd) return(0); cs_ftime(&serialdata->tps); serialdata->tpe=client->serialdata->tps; serialdata->tpe.millitm+=serialdata->oscam_ser_timeout+(l*(serialdata->oscam_ser_delay+1)); serialdata->tpe.time+=(serialdata->tpe.millitm/1000); serialdata->tpe.millitm%=1000; n=oscam_ser_write(client, buf, l); cs_ftime(&serialdata->tpe); cs_ddump_mask(D_CLIENT, buf, l, "send %d of %d bytes to %s in %ld msec", n, l, remote_txt(), 1000*(serialdata->tpe.time-serialdata->tps.time)+serialdata->tpe.millitm-serialdata->tps.millitm); if (n!=l) cs_log("transmit error. send %d of %d bytes only !", n, l); return(n); }
static int32_t radegast_recv(struct s_client *client, uchar *buf, int32_t l) { int32_t n; if (!client->pfd) return(-1); if (client->typ == 'c') { // server code if ((n=recv(client->pfd, buf, l, 0))>0) client->last=time((time_t *) 0); } else { // client code if ((n=recv(client->pfd, buf, l, 0))>0) { cs_ddump_mask(D_CLIENT, buf, n, "radegast: received %d bytes from %s", n, remote_txt()); client->last = time((time_t *) 0); if ((buf[0] == 0x02)&&(buf[1] == 0x12) && (buf[2] == 0x05)&&(buf[3] == 0x10)) return(n); // dcw received else if ((buf[0] == 0x02)&&(buf[1] == 0x02) && (buf[2] == 0x04)&&(buf[3] == 0x00)) return(n); // dcw no found else if ((buf[0] == 0x81)&&(buf[1] == 0x00)) return(n); // cmd unknown else n = -1;// no cmd radegast disconnect } } return(n); }
static int32_t radegast_recv(struct s_client *client, uchar *buf, int32_t l) { int32_t n; if (!client->pfd) return(-1); if (client->typ == 'c') { // server code if ((n=recv(client->pfd, buf, l, 0))>0) client->last=time((time_t *) 0); } else { // client code if ((n=recv(client->pfd, buf, l, 0))>0) { cs_ddump_mask(D_CLIENT, buf, n, "radegast: received %d bytes from %s", n, remote_txt()); client->last = time((time_t *) 0); if (buf[0] == 2) { // dcw received if (buf[3] != 0x10) { // dcw ok cs_log("radegast: no dcw"); n = -1; } } } } return(n); }
static int32_t oscam_ser_recv(struct s_client *client, uchar *xbuf, int32_t l) { int32_t s, p, n, r; uchar job=IS_BAD; static uchar lb; static int32_t have_lb=0; uchar *buf=xbuf+1; struct s_serial_client *serialdata=client->serialdata; if (!client->pfd) return(-1); cs_ftime(&serialdata->tps); serialdata->tpe=serialdata->tps; serialdata->tpe.millitm+=serialdata->oscam_ser_timeout; serialdata->tpe.time+=(serialdata->tpe.millitm/1000); serialdata->tpe.millitm%=1000; buf[0]=lb; for (s=p=r=0, n=have_lb; (s<4) && (p>=0); s++) { switch(s) { case 0: // STAGE 0: skip known garbage from DSR9500 if (oscam_ser_selrec(buf, 2-n, l, &n)) { if ((buf[0]==0x0A) && (buf[1]==0x0D)) p=(-4); if ((buf[0]==0x0D) && (buf[1]==0x0A)) p=(-4); } else p=(-3); have_lb=0; break; case 1: // STAGE 1: identify protocol p=(-3); if (oscam_ser_selrec(buf, 1, l, &n)) // now we have 3 bytes in buf { if((buf[0] == 0x04) && (buf[1] == 0x00) && (buf[2] == 0x02)) { //skip unsupported Advanced Serial Sharing Protocol HF 8900 oscam_ser_selrec(buf, 2, l, &n); // get rest 2 bytes to buffor p=(-4); have_lb=0; break; } else { p=(-2); if (client->typ == 'c') // HERE IS SERVER { job=IS_ECM; // assume ECM switch(buf[0]) { case 0x00: if( (buf[1]==0x01)&&(buf[2]==0x00) ) { p=P_GS; job=IS_LGO; serialdata->tpe.time++; } break; case 0x01: if( (buf[1]&0xf0)==0xb0 ) p=P_GBOX; else {p=P_SSSP; job=IS_PMT;} break; // pmt-request case 0x02: p=P_HSIC; break; case 0x03: switch(serialdata->oscam_ser_proto) { case P_SSSP : case P_GS : case P_DSR95 : p=serialdata->oscam_ser_proto; break; case P_AUTO : p=(buf[1]<0x30) ? P_SSSP : P_DSR95; break; // auto for GS is useless !! } break; case 0x04: p=P_DSR95; job=IS_ECHO; serialdata->dsr9500type=P_DSR_GNUSMAS; break; case 0x7E: p=P_ALPHA; if (buf[1]!=0x80) job=IS_BAD; break; case 0x80: case 0x81: p=P_BOMBA; break; } } else // HERE IS CLIENT { job=IS_DCW; // assume DCW switch(serialdata->oscam_ser_proto) { case P_HSIC : if ((buf[0]==4) && (buf[1]==4)) p=P_HSIC; break; case P_BOMBA: p=P_BOMBA; break; case P_DSR95: if (buf[0]==4) p=P_DSR95; break; case P_ALPHA: if (buf[0]==0x88) p=P_ALPHA; break; } } if ((serialdata->oscam_ser_proto!=p) && (serialdata->oscam_ser_proto!=P_AUTO)) p=(-2); } } break; case 2: // STAGE 2: examine length if (client->typ == 'c') switch(p) { case P_SSSP : r=(buf[1]<<8)|buf[2]; break; case P_BOMBA : r=buf[2]; break; case P_HSIC : if (oscam_ser_selrec(buf, 12, l, &n)) r=buf[14]; else p=(-1); break; case P_DSR95 : if( job==IS_ECHO ) { r=17*serialdata->samsung_dcw-3+serialdata->samsung_0a; serialdata->samsung_dcw=serialdata->samsung_0a=0; } else { if (oscam_ser_selrec(buf, 16, l, &n)) { uchar b; if (cs_atob(&b, (char *)buf+17, 1)<0) p=(-2); else { r=(b<<1); r+=(serialdata->dsr9500type==P_DSR_WITHSID)?4:0; } } else p=(-1); } break; case P_GS : if (job==IS_LGO) r=5; else { if (oscam_ser_selrec(buf, 1, l, &n)) r=(buf[3]<<8)|buf[2]; else p=(-1); } break; case P_ALPHA : r=-0x7F; // char specifying EOT break; case P_GBOX : r=((buf[1]&0xf)<<8) | buf[2]; serialdata->gbox_lens.cat_len = r; break; default : serialdata->dsr9500type=P_DSR_AUTO; } else switch(p) { case P_HSIC : r=(buf[2]==0x3A) ? 20 : 0; break; // 3A=DCW / FC=ECM was wrong case P_BOMBA : r=13; break; case P_DSR95 : r=14; break; case P_ALPHA : r=(buf[1]<<8)|buf[2]; break; // should be 16 always } break; case 3: // STAGE 3: get the rest ... if (r>0) // read r additional bytes { int32_t all = n+r; if( !oscam_ser_selrec(buf, r, l, &n) ) { cs_debug_mask(D_CLIENT, "not all data received, waiting another 50 ms"); serialdata->tpe.millitm+=50; if( !oscam_ser_selrec(buf, all-n, l, &n) ) p=(-1); } // auto detect DSR9500 protocol if( client->typ == 'c' && p==P_DSR95 && serialdata->dsr9500type==P_DSR_AUTO ) { serialdata->tpe.millitm+=20; if( oscam_ser_selrec(buf, 2, l, &n) ) { if( cs_atoi((char *)buf+n-2, 1, 1)==0xFFFFFFFF ) { switch( (buf[n-2]<<8)|buf[n-1] ) { case 0x0A0D : serialdata->dsr9500type=P_DSR_OPEN; break; case 0x0D0A : serialdata->dsr9500type=P_DSR_PIONEER; break; default : serialdata->dsr9500type=P_DSR_UNKNOWN; break; } }else{ if( oscam_ser_selrec(buf, 2, l, &n) ) if( cs_atoi((char *)buf+n-2, 1, 1)==0xFFFFFFFF ) serialdata->dsr9500type=P_DSR_UNKNOWN; else serialdata->dsr9500type=P_DSR_WITHSID; else { serialdata->dsr9500type=P_DSR_UNKNOWN; p=(-1); } } } else serialdata->dsr9500type=P_DSR_GNUSMAS; if( p ) cs_log("detected dsr9500-%s type receiver", dsrproto_txt[serialdata->dsr9500type]); } // gbox if( client->typ == 'c' && p==P_GBOX ) { int32_t j; for( j=0; (j<3) && (p>0); j++) switch( j ) { case 0: // PMT head if( !oscam_ser_selrec(buf, 3, l, &n) ) p=(-1); else if( !(buf[n-3]==0x02 && (buf[n-2]&0xf0)==0xb0) ) p=(-2); break; case 1: // PMT + ECM header serialdata->gbox_lens.pmt_len=((buf[n-2]&0xf)<<8)|buf[n-1]; if( !oscam_ser_selrec(buf, serialdata->gbox_lens.pmt_len+3, l, &n) ) p=(-1); break; case 2: // ECM + ECM PID serialdata->gbox_lens.ecm_len=((buf[n-2]&0xf)<<8)|buf[n-1]; if( !oscam_ser_selrec(buf, serialdata->gbox_lens.ecm_len+4, l, &n) ) p=(-1); } } // gbox } else if (r<0) // read until specified char (-r) { while((buf[n-1]!=(-r)) && (p>0)) if (!oscam_ser_selrec(buf, 1, l, &n)) p=(-1); } break; } } if (p==(-2) || p==(-1)) { oscam_ser_selrec(buf, l-n, l, &n); // flush buffer serialdata->serial_errors++; } cs_ftime(&serialdata->tpe); cs_ddump_mask(D_CLIENT, buf, n, "received %d bytes from %s in %ld msec", n, remote_txt(), 1000*(serialdata->tpe.time-serialdata->tps.time)+serialdata->tpe.millitm-serialdata->tps.millitm); client->last=serialdata->tpe.time; switch(p) { case (-1): if (client->typ == 'c'&&(n>2)&&(buf[0]==2)&&(buf[1]==2)&&(buf[2]==2)) { oscam_ser_disconnect(); cs_log("humax powered on"); // this is nice ;) } else { if(client->typ == 'c' && buf[0] == 0x1 && buf[1] == 0x08 && buf[2] == 0x20 && buf[3] == 0x08) { oscam_ser_disconnect(); cs_log("ferguson powered on"); // this is nice to ;) } else cs_log(incomplete, n); } break; case (-2): cs_debug_mask(D_CLIENT, "unknown request or garbage"); break; } xbuf[0]=(uchar) ((job<<4) | p); return((p<0)?0:n+1); }
static int32_t cacheex_add_to_cache_int(struct s_client *cl, ECM_REQUEST *er, int8_t csp) { if(er->rc >= E_NOTFOUND) { return 0; } if(!cl) { return 0; } if(!csp && cl->reader && cl->reader->cacheex.mode != 2) //from reader { cs_debug_mask(D_CACHEEX, "CACHEX received, but disabled for %s", username(cl)); return 0; } if(!csp && !cl->reader && cl->account && cl->account->cacheex.mode != 3) //from user { cs_debug_mask(D_CACHEEX, "CACHEX received, but disabled for %s", username(cl)); return 0; } if(!csp && !cl->reader && !cl->account) //not active! { cs_debug_mask(D_CACHEEX, "CACHEX received, but invalid client state %s", username(cl)); return 0; } uint8_t i, c; uint8_t null = 0; for(i = 0; i < 16; i += 4) { c = ((er->cw[i] + er->cw[i + 1] + er->cw[i + 2]) & 0xff); null |= (er->cw[i] | er->cw[i + 1] | er->cw[i + 2]); if(er->cw[i + 3] != c) { cs_ddump_mask(D_CACHEEX, er->cw, 16, "push received cw with chksum error from %s", csp ? "csp" : username(cl)); cl->cwcacheexerr++; if(cl->account) { cl->account->cwcacheexerr++; } return 0; } } if(null == 0 || chk_is_null_CW(er->cw)) { cs_ddump_mask(D_CACHEEX, er->cw, 16, "push received null cw from %s", csp ? "csp" : username(cl)); cl->cwcacheexerr++; if(cl->account) { cl->account->cwcacheexerr++; } return 0; } er->grp |= cl->grp; //ok for mode2 reader too: cl->reader->grp er->rc = E_CACHEEX; er->cacheex_src = cl; er->selected_reader = cl->reader; er->client = NULL; //No Owner! So no fallback! if(check_client(cl)) { cl->cwcacheexgot++; if(cl->account) { cl->account->cwcacheexgot++; } first_client->cwcacheexgot++; } add_hitcache(cl, er); //we have to call it before add_cache, because in chk_process we could remove it! add_cache(er); cacheex_add_stats(cl, er->caid, er->srvid, er->prid, 1); cs_writelock(&ecm_pushed_deleted_lock); er->next = ecm_pushed_deleted; ecm_pushed_deleted = er; cs_writeunlock(&ecm_pushed_deleted_lock); return 1; //NO free, we have to wait cache push out stuff ends. }
int32_t gbox_cmd_hello(struct s_client *cli, uchar *data, int32_t n) { struct gbox_peer *peer = cli->gbox; int32_t i; int32_t ncards_in_msg = 0; int32_t payload_len = n; //TODO: checkcode_len can be made void int32_t checkcode_len = 0; int32_t hostname_len = 0; int32_t footer_len = 0; uint8_t *ptr = 0; if(!(data[0] == 0x48 && data[1] == 0x49)) // if not MSG_HELLO1 { gbox_decompress(data, &payload_len); } cs_ddump_mask(D_READER, data, payload_len, "gbox: decompressed data (%d bytes):", payload_len); if((data[0x0B] == 0) | ((data[0x0A] == 1) && (data[0x0B] == 0x80))) { if(peer->gbox.cards) { gbox_remove_cards_without_goodsids(peer->gbox.cards); } else { peer->gbox.cards = ll_create("peer.cards"); } } if((data[0xB] & 0xF) == 0) { checkcode_len = 7; hostname_len = data[payload_len - 1]; footer_len = hostname_len + 2; } if(data[0] == 0x48 && data[1] == 0x49) // if MSG_HELLO1 { ptr = data + 11; } else { ptr = data + 12; } while(ptr < data + payload_len - footer_len - checkcode_len - 1) { uint16_t caid; uint32_t provid; uint32_t provid1; switch(ptr[0]) { //Viaccess case 0x05: caid = ptr[0] << 8; provid = ptr[1] << 16 | ptr[2] << 8 | ptr[3]; break; //Cryptoworks case 0x0D: caid = ptr[0] << 8 | ptr[1]; provid = ptr[2]; break; default: caid = ptr[0] << 8 | ptr[1]; provid = ptr[2] << 8 | ptr[3]; break; } //caid check if(chk_ctab(caid, &cli->reader->ctab)) { provid1 = ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3]; uint8_t ncards = ptr[4]; ptr += 5; for(i = 0; i < ncards; i++) { // for all n cards and current caid/provid, // create card info from data and add card to peer.cards struct gbox_card *card; if(!cs_malloc(&card, sizeof(struct gbox_card))) { continue; } card->caid = caid; card->provid = provid; card->provid_1 = provid1; card->slot = ptr[0]; card->dist = ptr[1] & 0xf; card->lvl = ptr[1] >> 4; card->peer_id = ptr[2] << 8 | ptr[3]; ptr += 4; if((cli->reader->gbox_maxdist >= card->dist) && (card->peer_id != local_gbox.id)) { LL_ITER it = ll_iter_create(peer->gbox.cards); struct gbox_card *card_s; uint8_t v_card = 0; while((card_s = ll_iter_next(&it))) // don't add card if already in peer.cards list { if(card_s->peer_id == card->peer_id && card_s->provid_1 == card->provid_1) { gbox_free_card(card); card = NULL; v_card = 1; break; } } if(v_card != 1) // new card - not in list { card->badsids = ll_create("badsids"); card->goodsids = ll_create("goodsids"); ll_append(peer->gbox.cards, card); ncards_in_msg++; cs_debug_mask(D_READER, " card: caid=%04x, provid=%06x, slot=%d, level=%d, dist=%d, peer=%04x", card->caid, card->provid, card->slot, card->lvl, card->dist, card->peer_id); } } else // don't add card { gbox_free_card(card); card = NULL; } cli->reader->tcp_connected = 2; // we have card } // end for ncards } else {
static void process_clients(void) { int32_t i, k, j, rc, pfdcount = 0; struct s_client *cl; struct s_reader *rdr; struct pollfd *pfd; struct s_client **cl_list; struct timeb start, end; // start time poll, end time poll uint32_t cl_size = 0; uchar buf[10]; if (pipe(thread_pipe) == -1) { printf("cannot create pipe, errno=%d\n", errno); exit(1); } cl_size = chk_resize_cllist(&pfd, &cl_list, 0, 100); pfd[pfdcount].fd = thread_pipe[0]; pfd[pfdcount].events = POLLIN | POLLPRI; cl_list[pfdcount] = NULL; while (!exit_oscam) { pfdcount = 1; //connected tcp clients for (cl=first_client->next; cl; cl=cl->next) { if (cl->init_done && !cl->kill && cl->pfd && cl->typ=='c' && !cl->is_udp) { if (cl->pfd && !cl->thread_active) { cl_size = chk_resize_cllist(&pfd, &cl_list, cl_size, pfdcount); cl_list[pfdcount] = cl; pfd[pfdcount].fd = cl->pfd; pfd[pfdcount++].events = POLLIN | POLLPRI; } } //reader: //TCP: // - TCP socket must be connected // - no active init thread //UDP: // - connection status ignored // - no active init thread rdr = cl->reader; if (rdr && cl->typ=='p' && cl->init_done) { if (cl->pfd && !cl->thread_active && ((rdr->tcp_connected && rdr->ph.type==MOD_CONN_TCP)||(rdr->ph.type==MOD_CONN_UDP))) { cl_size = chk_resize_cllist(&pfd, &cl_list, cl_size, pfdcount); cl_list[pfdcount] = cl; pfd[pfdcount].fd = cl->pfd; pfd[pfdcount++].events = (POLLIN | POLLPRI); } } } //server (new tcp connections or udp messages) for (k = 0; k < CS_MAX_MOD; k++) { struct s_module *module = &modules[k]; if ((module->type & MOD_CONN_NET)) { for (j = 0; j < module->ptab.nports; j++) { if (module->ptab.ports[j].fd) { cl_size = chk_resize_cllist(&pfd, &cl_list, cl_size, pfdcount); cl_list[pfdcount] = NULL; pfd[pfdcount].fd = module->ptab.ports[j].fd; pfd[pfdcount++].events = (POLLIN | POLLPRI); } } } } if (pfdcount >= 1024) cs_log("WARNING: too many users!"); cs_ftime(&start); // register start time rc = poll(pfd, pfdcount, 5000); if (rc<1) continue; cs_ftime(&end); // register end time for (i=0; i<pfdcount&&rc>0; i++) { if (pfd[i].revents == 0) continue; // skip sockets with no changes rc--; //event handled! cs_debug_mask(D_TRACE, "[OSCAM] new event %d occurred on fd %d after %ld ms inactivity", pfd[i].revents, pfd[i].fd,1000*(end.time-start.time)+end.millitm-start.millitm); //clients cl = cl_list[i]; if (cl && !is_valid_client(cl)) continue; if (pfd[i].fd == thread_pipe[0] && (pfd[i].revents & (POLLIN | POLLPRI))) { // a thread ended and cl->pfd should be added to pollfd list again (thread_active==0) int32_t len= read(thread_pipe[0], buf, sizeof(buf)); if(len == -1){ cs_debug_mask(D_TRACE, "[OSCAM] Reading from pipe failed (errno=%d %s)", errno, strerror(errno)); } cs_ddump_mask(D_TRACE, buf, len, "[OSCAM] Readed:"); continue; } //clients // message on an open tcp connection if (cl && cl->init_done && cl->pfd && (cl->typ == 'c' || cl->typ == 'm')) { if (pfd[i].fd == cl->pfd && (pfd[i].revents & (POLLHUP | POLLNVAL | POLLERR))) { //client disconnects kill_thread(cl); continue; } if (pfd[i].fd == cl->pfd && (pfd[i].revents & (POLLIN | POLLPRI))) { add_job(cl, ACTION_CLIENT_TCP, NULL, 0); } } //reader // either an ecm answer, a keepalive or connection closed from a proxy // physical reader ('r') should never send data without request rdr = NULL; struct s_client *cl2 = NULL; if (cl && cl->typ == 'p'){ rdr = cl->reader; if(rdr) cl2 = rdr->client; } if (rdr && cl2 && cl2->init_done) { if (cl2->pfd && pfd[i].fd == cl2->pfd && (pfd[i].revents & (POLLHUP | POLLNVAL | POLLERR))) { //connection to remote proxy was closed //oscam should check for rdr->tcp_connected and reconnect on next ecm request sent to the proxy network_tcp_connection_close(rdr, "closed"); rdr_debug_mask(rdr, D_READER, "connection closed"); } if (cl2->pfd && pfd[i].fd == cl2->pfd && (pfd[i].revents & (POLLIN | POLLPRI))) { add_job(cl2, ACTION_READER_REMOTE, NULL, 0); } } //server sockets // new connection on a tcp listen socket or new message on udp listen socket if (!cl && (pfd[i].revents & (POLLIN | POLLPRI))) { for (k = 0; k < CS_MAX_MOD; k++) { struct s_module *module = &modules[k]; if ((module->type & MOD_CONN_NET)) { for (j = 0; j < module->ptab.nports; j++) { if (module->ptab.ports[j].fd && module->ptab.ports[j].fd == pfd[i].fd) { accept_connection(module, k, j); } } } } } } cs_ftime(&start); // register start time for new poll next run first_client->last=time((time_t *)0); } free(pfd); free(cl_list); return; }
int32_t viaccess_reassemble_emm(uchar *buffer, uint32_t *len) { static uchar emm_global[512]; static int32_t emm_global_len = 0; int32_t pos=0, i; uint32_t k; // Viaccess if (*len>500) return 0; switch(buffer[0]) { case 0x8c: case 0x8d: // emm-s part 1 if (!memcmp(emm_global, buffer, *len)) return 0; // copy first part of the emm-s memcpy(emm_global, buffer, *len); emm_global_len=*len; //cs_ddump_mask(D_READER, buffer, len, "viaccess global emm:"); return 0; case 0x8e: // emm-s part 2 if (!emm_global_len) return 0; //extract nanos from emm-gh and emm-s uchar emmbuf[512]; cs_debug_mask(D_DVBAPI, "[viaccess] %s: start extracting nanos", __func__); //extract from emm-gh for (i=3; i<emm_global_len; i+=emm_global[i+1]+2) { //copy nano (length determined by i+1) memcpy(emmbuf+pos, emm_global+i, emm_global[i+1]+2); pos+=emm_global[i+1]+2; } if (buffer[2]==0x2c) { //add 9E 20 nano + first 32 bytes of emm content memcpy(emmbuf+pos, "\x9E\x20", 2); memcpy(emmbuf+pos+2, buffer+7, 32); pos+=34; //add F0 08 nano + 8 subsequent bytes of emm content memcpy(emmbuf+pos, "\xF0\x08", 2); memcpy(emmbuf+pos+2, buffer+39, 8); pos+=10; } else { //extract from variable emm-s for (k=7; k<(*len); k+=buffer[k+1]+2) { //copy nano (length determined by k+1) memcpy(emmbuf+pos, buffer+k, buffer[k+1]+2); pos+=buffer[k+1]+2; } } cs_ddump_mask(D_DVBAPI, buffer, *len, "[viaccess] %s: %s emm-s", __func__, (buffer[2]==0x2c) ? "fixed" : "variable"); dvbapi_sort_nanos(buffer+7, emmbuf, pos); pos+=7; //calculate emm length and set it on position 2 buffer[2]=pos-3; cs_ddump_mask(D_DVBAPI, emm_global, emm_global_len, "[viaccess] %s: emm-gh", __func__); cs_ddump_mask(D_DVBAPI, buffer, pos, "[viaccess] %s: assembled emm", __func__); *len=pos; break; } return 1; }
static int32_t ghttp_recv_chk(struct s_client *client, uchar *dcw, int32_t *rc, uchar *buf, int32_t n) { char *data; char *hdrstr; uchar *content; int rcode, len, clen = 0; s_ghttp *context = (s_ghttp *)client->ghttp; ECM_REQUEST *er = NULL; if(n < 5) { return -1; } data = strstr((char *)buf, "HTTP/1.1 "); if(!data || ll_count(context->ecm_q) > 6) { cs_debug_mask(D_CLIENT, "%s: non http or otherwise corrupt response: %s", client->reader->label, buf); cs_ddump_mask(D_CLIENT, buf, n, "%s: ", client->reader->label); network_tcp_connection_close(client->reader, "receive error"); NULLFREE(context->session_id); ll_clear(context->ecm_q); return -1; } LL_ITER itr = ll_iter_create(context->ecm_q); er = (ECM_REQUEST *)ll_iter_next(&itr); rcode = _get_int_header(buf, "HTTP/1.1 "); clen = _get_int_header(buf, "Content-Length: "); content = (uchar *)(strstr(data, "\r\n\r\n") + 4); hdrstr = _get_header_substr(buf, "ETag: \"", "\"\r\n"); if(hdrstr) { NULLFREE(context->host_id); context->host_id = (uchar *)hdrstr; cs_debug_mask(D_CLIENT, "%s: new name: %s", client->reader->label, context->host_id); len = b64decode(context->host_id); if(len == 0 || len >= 64) { NULLFREE(context->host_id); } else { cs_debug_mask(D_CLIENT, "%s: redirected...", client->reader->label); NULLFREE(context->session_id); ll_clear_data(ghttp_ignored_contexts); ll_clear(context->ecm_q); return -1; } } hdrstr = _get_header_substr(buf, "ETag: W/\"", "\"\r\n"); if(hdrstr) { NULLFREE(context->fallback_id); context->fallback_id = (uchar *)hdrstr; cs_debug_mask(D_CLIENT, "%s: new fallback name: %s", client->reader->label, context->fallback_id); len = b64decode(context->fallback_id); if(len == 0 || len >= 64) { NULLFREE(context->fallback_id); } } hdrstr = _get_header(buf, "Set-Cookie: GSSID="); if(hdrstr) { NULLFREE(context->session_id); context->session_id = (uchar *)hdrstr; cs_debug_mask(D_CLIENT, "%s: set session_id to: %s", client->reader->label, context->session_id); } // buf[n] = '\0'; // cs_ddump_mask(D_TRACE, content, clen, "%s: reply\n%s", client->reader->label, buf); if(rcode < 200 || rcode > 204) { cs_debug_mask(D_CLIENT, "%s: http error code %d", client->reader->label, rcode); data = strstr((char *)buf, "Content-Type: application/octet-stream"); // if not octet-stream, google error. need reconnect? if(data) // we have error info string in the post content { if(clen > 0) { content[clen] = '\0'; cs_debug_mask(D_CLIENT, "%s: http error message: %s", client->reader->label, content); } } if(rcode == 503) { if(er && _is_post_context(context->post_contexts, er, false)) { if(_swap_hosts(context)) { cs_debug_mask(D_CLIENT, "%s: switching to fallback", client->reader->label); } else { cs_debug_mask(D_CLIENT, "%s: recv_chk got 503 despite post, trying reconnect", client->reader->label); network_tcp_connection_close(client->reader, "reconnect"); ll_clear(context->ecm_q); } } else { // on 503 cache timeout, retry with POST immediately (and switch to POST for subsequent) if(er) { _set_pid_status(context->post_contexts, er->onid, er->tsid, er->srvid, 0); cs_debug_mask(D_CLIENT, "%s: recv_chk got 503, trying direct post", client->reader->label); _ghttp_post_ecmdata(client, er); } } } else if(rcode == 401) { NULLFREE(context->session_id); if(er) { cs_debug_mask(D_CLIENT, "%s: session expired, trying direct post", client->reader->label); _ghttp_post_ecmdata(client, er); } } else if(rcode == 403) { client->reader->enable = 0; network_tcp_connection_close(client->reader, "login failure"); ll_clear(context->ecm_q); cs_log("%s: invalid username/password, disabling reader.", client->reader->label); } // not sure if this is needed on failure, copied from newcamd *rc = 0; memset(dcw, 0, 16); return -1; } // successful http reply (200 ok or 204 no content) hdrstr = _get_header(buf, "Pragma: context-ignore="); if(hdrstr) { if(clen > 1) { cs_ddump_mask(D_CLIENT, content, clen, "%s: pmt ignore reply - %s (%d pids)", client->reader->label, hdrstr, clen / 2); uint32_t onid = 0, tsid = 0, sid = 0; if(sscanf(hdrstr, "%4x-%4x-%4x", &onid, &tsid, &sid) == 3) { _set_pids_status(ghttp_ignored_contexts, onid, tsid, sid, content, clen); } NULLFREE(hdrstr); return -1; } NULLFREE(hdrstr); } data = strstr((char *)buf, "Pragma: context-ignore-clear"); if(data) { cs_debug_mask(D_CLIENT, "%s: clearing local ignore list (size %d)", client->reader->label, ll_count(ghttp_ignored_contexts)); ll_clear_data(ghttp_ignored_contexts); } // switch back to cache get after rapid ecm response (arbitrary atm), only effect is a slight bw save for client if(!er || _is_post_context(context->post_contexts, er, false)) { data = strstr((char *)buf, "Pragma: cached"); if(data || (client->cwlastresptime > 0 && client->cwlastresptime < 640)) { cs_debug_mask(D_CLIENT, "%s: probably cached cw (%d ms), switching back to cache get for next req", client->reader->label, client->cwlastresptime); if(er) { _is_post_context(context->post_contexts, er, true); } } } if(clen == 16) // cw in content { memcpy(dcw, content, 16); *rc = 1; er = ll_remove_first(context->ecm_q); if(!er) { return -1; } cs_ddump_mask(D_TRACE, dcw, 16, "%s: cw recv chk for idx %d", client->reader->label, er->idx); return er->idx; } else { if(clen != 0) { cs_ddump_mask(D_CLIENT, content, clen, "%s: recv_chk fail, clen = %d", client->reader->label, clen); } } return -1; }
void azbox_send_dcw(struct s_client *client, ECM_REQUEST *er) { cs_debug_mask(D_DVBAPI, LOG_PREFIX "send_dcw"); FILE *ecmtxt; if ((ecmtxt = fopen(ECMINFO_FILE, "w"))) { char tmp[25]; if(er->rc <= E_CACHEEX) { fprintf(ecmtxt, "caid: 0x%04X\npid: 0x%04X\nprov: 0x%06X\n", er->caid, er->pid, (uint) er->prid); fprintf(ecmtxt, "reader: %s\n", er->selected_reader->label); if (is_cascading_reader(er->selected_reader)) fprintf(ecmtxt, "from: %s\n", er->selected_reader->device); else fprintf(ecmtxt, "from: local\n"); fprintf(ecmtxt, "protocol: %s\n", reader_get_type_desc(er->selected_reader, 1)); fprintf(ecmtxt, "hops: %d\n", er->selected_reader->currenthops); fprintf(ecmtxt, "ecm time: %.3f\n", (float) client->cwlastresptime/1000); fprintf(ecmtxt, "cw0: %s\n", cs_hexdump(1,demux[0].lastcw[0],8, tmp, sizeof(tmp))); fprintf(ecmtxt, "cw1: %s\n", cs_hexdump(1,demux[0].lastcw[1],8, tmp, sizeof(tmp))); fclose(ecmtxt); ecmtxt = NULL; } else { fprintf(ecmtxt, "ECM information not found\n"); fclose(ecmtxt); } } openxcas_busy = 0; int32_t i; for (i=0; i < MAX_DEMUX; i++) { if (er->rc >= E_NOTFOUND) { cs_debug_mask(D_DVBAPI, "cw not found"); if (demux[i].pidindex==-1) dvbapi_try_next_caid(i); openxcas_stop_filter(openxcas_stream_id, OPENXCAS_FILTER_ECM); openxcas_remove_filter(openxcas_stream_id, OPENXCAS_FILTER_ECM); unsigned char mask[12]; unsigned char comp[12]; memset(&mask, 0x00, sizeof(mask)); memset(&comp, 0x00, sizeof(comp)); mask[0] = 0xfe; comp[0] = 0x80; if (openxcas_add_filter(openxcas_stream_id, OPENXCAS_FILTER_ECM, 0, 0xffff, openxcas_ecm_pid, mask, comp, (void *)azbox_openxcas_ecm_callback) < 0) { cs_log(LOG_PREFIX "unable to add ecm filter (0)"); if (openxcas_add_filter(openxcas_stream_id, OPENXCAS_FILTER_ECM, openxcas_caid, 0xffff, openxcas_ecm_pid, mask, comp, (void *)azbox_openxcas_ecm_callback) < 0) cs_log(LOG_PREFIX "unable to add ecm filter (%04x)", openxcas_caid); else cs_debug_mask(D_DVBAPI, LOG_PREFIX "ecm filter added, pid = %x, caid = %x", openxcas_ecm_pid, openxcas_caid); } else cs_debug_mask(D_DVBAPI, LOG_PREFIX "ecm filter added, pid = %x, caid = %x", openxcas_ecm_pid, 0); if (openxcas_start_filter(openxcas_stream_id, openxcas_seq, OPENXCAS_FILTER_ECM) < 0) cs_log(LOG_PREFIX "unable to start ecm filter"); else cs_debug_mask(D_DVBAPI, LOG_PREFIX "ecm filter started"); return; } } unsigned char nullcw[8]; memset(nullcw, 0, 8); int32_t n; for (n=0;n<2;n++) { if (memcmp(er->cw + (n * 8), demux[0].lastcw[n], 8) && memcmp(er->cw + (n * 8), nullcw, 8)) { memcpy(demux[0].lastcw[n], er->cw + (n * 8), 8); memcpy(openxcas_cw + (n * 8), er->cw + (n * 8), 8); } } if (openxcas_set_key(openxcas_stream_id, openxcas_seq, 0, openxcas_cipher_idx, openxcas_cw, openxcas_cw + 8) != 1) cs_log(LOG_PREFIX "set cw failed"); else cs_ddump_mask(D_DVBAPI, openxcas_cw, 16, LOG_PREFIX "write cws to descrambler"); }
void *work_thread(void *ptr) { struct job_data *data = (struct job_data *)ptr; struct s_client *cl = data->cl; struct s_reader *reader = cl->reader; struct timeb start, end; // start time poll, end time poll struct job_data tmp_data; struct pollfd pfd[1]; pthread_setspecific(getclient, cl); cl->thread = pthread_self(); cl->thread_active = 1; set_work_thread_name(data); struct s_module *module = get_module(cl); uint16_t bufsize = module->bufsize; //CCCam needs more than 1024bytes! if(!bufsize) { bufsize = 1024; } uint8_t *mbuf; if(!cs_malloc(&mbuf, bufsize)) { return NULL; } cl->work_mbuf = mbuf; // Track locally allocated data, because some callback may call cs_exit/cs_disconect_client/pthread_exit and then mbuf would be leaked int32_t n = 0, rc = 0, i, idx, s; uint8_t dcw[16]; int8_t restart_reader = 0; while(cl->thread_active) { cs_ftime(&start); // register start time while(cl->thread_active) { if(!cl || cl->kill || !is_valid_client(cl)) { pthread_mutex_lock(&cl->thread_lock); cl->thread_active = 0; pthread_mutex_unlock(&cl->thread_lock); cs_debug_mask(D_TRACE, "ending thread (kill)"); __free_job_data(cl, data); cl->work_mbuf = NULL; // Prevent free_client from freeing mbuf (->work_mbuf) free_client(cl); if(restart_reader) { restart_cardreader(reader, 0); } NULLFREE(mbuf); pthread_exit(NULL); return NULL; } if(data && data->action != ACTION_READER_CHECK_HEALTH) { cs_debug_mask(D_TRACE, "data from add_job action=%d client %c %s", data->action, cl->typ, username(cl)); } if(!data) { if(!cl->kill && cl->typ != 'r') { client_check_status(cl); } // do not call for physical readers as this might cause an endless job loop pthread_mutex_lock(&cl->thread_lock); if(cl->joblist && ll_count(cl->joblist) > 0) { LL_ITER itr = ll_iter_create(cl->joblist); data = ll_iter_next_remove(&itr); if(data) { set_work_thread_name(data); } //cs_debug_mask(D_TRACE, "start next job from list action=%d", data->action); } pthread_mutex_unlock(&cl->thread_lock); } if(!data) { /* for serial client cl->pfd is file descriptor for serial port not socket for example: pfd=open("/dev/ttyUSB0"); */ if(!cl->pfd || module->listenertype == LIS_SERIAL) { break; } pfd[0].fd = cl->pfd; pfd[0].events = POLLIN | POLLPRI; pthread_mutex_lock(&cl->thread_lock); cl->thread_active = 2; pthread_mutex_unlock(&cl->thread_lock); rc = poll(pfd, 1, 3000); pthread_mutex_lock(&cl->thread_lock); cl->thread_active = 1; pthread_mutex_unlock(&cl->thread_lock); if(rc > 0) { cs_ftime(&end); // register end time cs_debug_mask(D_TRACE, "[OSCAM-WORK] new event %d occurred on fd %d after %"PRId64" ms inactivity", pfd[0].revents, pfd[0].fd, comp_timeb(&end, &start)); data = &tmp_data; data->ptr = NULL; cs_ftime(&start); // register start time for new poll next run if(reader) { data->action = ACTION_READER_REMOTE; } else { if(cl->is_udp) { data->action = ACTION_CLIENT_UDP; data->ptr = mbuf; data->len = bufsize; } else { data->action = ACTION_CLIENT_TCP; } if(pfd[0].revents & (POLLHUP | POLLNVAL | POLLERR)) { cl->kill = 1; } } } } if(!data) { continue; } if(!reader && data->action < ACTION_CLIENT_FIRST) { __free_job_data(cl, data); break; } if(!data->action) { break; } struct timeb actualtime; cs_ftime(&actualtime); int32_t gone = comp_timeb(&actualtime, &data->time); if(data != &tmp_data && gone > (int) cfg.ctimeout+1000) { cs_debug_mask(D_TRACE, "dropping client data for %s time %dms", username(cl), gone); __free_job_data(cl, data); continue; } if(data != &tmp_data) { cl->work_job_data = data; } // Track the current job_data switch(data->action) { case ACTION_READER_IDLE: reader_do_idle(reader); break; case ACTION_READER_REMOTE: s = check_fd_for_data(cl->pfd); if(s == 0) // no data, another thread already read from fd? { break; } if(s < 0) { if(reader->ph.type == MOD_CONN_TCP) { network_tcp_connection_close(reader, "disconnect"); } break; } rc = reader->ph.recv(cl, mbuf, bufsize); if(rc < 0) { if(reader->ph.type == MOD_CONN_TCP) { network_tcp_connection_close(reader, "disconnect on receive"); } break; } cl->last = time(NULL); // *********************************** TO BE REPLACE BY CS_FTIME() LATER **************** idx = reader->ph.c_recv_chk(cl, dcw, &rc, mbuf, rc); if(idx < 0) { break; } // no dcw received if(!idx) { idx = cl->last_idx; } reader->last_g = time(NULL); // *********************************** TO BE REPLACE BY CS_FTIME() LATER **************** // for reconnect timeout for(i = 0, n = 0; i < cfg.max_pending && n == 0; i++) { if(cl->ecmtask[i].idx == idx) { cl->pending--; casc_check_dcw(reader, i, rc, dcw); n++; } } break; case ACTION_READER_RESET: cardreader_do_reset(reader); break; case ACTION_READER_ECM_REQUEST: reader_get_ecm(reader, data->ptr); break; case ACTION_READER_EMM: reader_do_emm(reader, data->ptr); break; case ACTION_READER_CARDINFO: reader_do_card_info(reader); break; case ACTION_READER_INIT: if(!cl->init_done) { reader_init(reader); } break; case ACTION_READER_RESTART: cl->kill = 1; restart_reader = 1; break; case ACTION_READER_RESET_FAST: reader->card_status = CARD_NEED_INIT; cardreader_do_reset(reader); break; case ACTION_READER_CHECK_HEALTH: cardreader_do_checkhealth(reader); break; case ACTION_READER_CAPMT_NOTIFY: if(reader->ph.c_capmt) { reader->ph.c_capmt(cl, data->ptr); } break; case ACTION_CLIENT_UDP: n = module->recv(cl, data->ptr, data->len); if(n < 0) { break; } module->s_handler(cl, data->ptr, n); break; case ACTION_CLIENT_TCP: s = check_fd_for_data(cl->pfd); if(s == 0) // no data, another thread already read from fd? { break; } if(s < 0) // system error or fd wants to be closed { cl->kill = 1; // kill client on next run continue; } n = module->recv(cl, mbuf, bufsize); if(n < 0) { cl->kill = 1; // kill client on next run continue; } module->s_handler(cl, mbuf, n); break; case ACTION_CACHEEX_TIMEOUT: #ifdef CS_CACHEEX cacheex_timeout(data->ptr); #endif break; case ACTION_FALLBACK_TIMEOUT: fallback_timeout(data->ptr); break; case ACTION_CLIENT_TIMEOUT: ecm_timeout(data->ptr); break; case ACTION_ECM_ANSWER_READER: chk_dcw(data->ptr); break; case ACTION_ECM_ANSWER_CACHE: write_ecm_answer_fromcache(data->ptr); break; case ACTION_CLIENT_INIT: if(module->s_init) { module->s_init(cl); } cl->is_udp = module->type == MOD_CONN_UDP; cl->init_done = 1; break; case ACTION_CLIENT_IDLE: if(module->s_idle) { module->s_idle(cl); } else { cs_log("user %s reached %d sec idle limit.", username(cl), cfg.cmaxidle); cl->kill = 1; } break; case ACTION_CACHE_PUSH_OUT: { #ifdef CS_CACHEEX ECM_REQUEST *er = data->ptr; int32_t res = 0, stats = -1; // cc-nodeid-list-check if(reader) { if(reader->ph.c_cache_push_chk && !reader->ph.c_cache_push_chk(cl, er)) { break; } res = reader->ph.c_cache_push(cl, er); stats = cacheex_add_stats(cl, er->caid, er->srvid, er->prid, 0); } else { if(module->c_cache_push_chk && !module->c_cache_push_chk(cl, er)) { break; } res = module->c_cache_push(cl, er); } debug_ecm(D_CACHEEX, "pushed ECM %s to %s res %d stats %d", buf, username(cl), res, stats); cl->cwcacheexpush++; if(cl->account) { cl->account->cwcacheexpush++; } first_client->cwcacheexpush++; #endif break; } case ACTION_CLIENT_KILL: cl->kill = 1; break; case ACTION_CLIENT_SEND_MSG: { #ifdef MODULE_CCCAM struct s_clientmsg *clientmsg = (struct s_clientmsg *)data->ptr; cc_cmd_send(cl, clientmsg->msg, clientmsg->len, clientmsg->cmd); #endif break; } } // switch __free_job_data(cl, data); } if(thread_pipe[1] && (mbuf[0] != 0x00)) { cs_ddump_mask(D_TRACE, mbuf, 1, "[OSCAM-WORK] Write to pipe:"); if(write(thread_pipe[1], mbuf, 1) == -1) // wakeup client check { cs_debug_mask(D_TRACE, "[OSCAM-WORK] Writing to pipe failed (errno=%d %s)", errno, strerror(errno)); } } // Check for some race condition where while we ended, another thread added a job pthread_mutex_lock(&cl->thread_lock); if(cl->joblist && ll_count(cl->joblist) > 0) { pthread_mutex_unlock(&cl->thread_lock); continue; } else { cl->thread_active = 0; pthread_mutex_unlock(&cl->thread_lock); break; } } cl->thread_active = 0; cl->work_mbuf = NULL; // Prevent free_client from freeing mbuf (->work_mbuf) NULLFREE(mbuf); pthread_exit(NULL); return NULL; }
static int32_t ghttp_capmt_notify(struct s_client *client, struct demux_s *demux) { uchar req[640], lenhdr[64] = ""; uchar *pids = NULL; uchar *end; char *encauth = NULL; int32_t ret; int8_t i, pids_len = 0, offs = 0; s_ghttp *context = (s_ghttp *)client->ghttp; if(!context) { return -1; } cs_debug_mask(D_CLIENT, "%s: capmt %x-%x-%x %d pids on adapter %d mask %x dmx index %d", client->reader->label, demux->onid, demux->tsid, demux->program_number, demux->ECMpidcount, demux->adapter_index, demux->ca_mask, demux->demux_index); if(demux->ECMpidcount > 0) { if(cs_malloc(&pids, demux->ECMpidcount * 8)) { pids_len = demux->ECMpidcount * 8; for(i = 0; i < demux->ECMpidcount; i++) { i2b_buf(2, demux->ECMpids[i].ECM_PID, pids + offs); i2b_buf(2, demux->ECMpids[i].CAID, pids + (offs += 2)); i2b_buf(4, demux->ECMpids[i].PROVID, pids + (offs += 2)); offs += 4; } snprintf((char *)lenhdr, sizeof(lenhdr), "\r\nContent-Length: %d", pids_len); } else { return -1; } } if(!context->host_id) { context->host_id = (uchar *)cs_strdup(client->reader->device); } encauth = _ghttp_basic_auth(client); if(encauth) // basic auth login { ret = snprintf((char *)req, sizeof(req), "%s /api/p/%x/%x/%x/%x/%x HTTP/1.1\r\nHost: %s\r\nAuthorization: Basic %s%s\r\n\r\n", ((pids_len > 0) ? "POST" : "GET"), demux->onid, demux->tsid, demux->program_number, demux->ECMpidcount, demux->enigma_namespace, context->host_id, encauth, lenhdr); free(encauth); } else { if(context->session_id) // session exists { ret = snprintf((char *)req, sizeof(req), "%s /api/p/%s/%x/%x/%x/%x/%x HTTP/1.1\r\nHost: %s%s\r\n\r\n", ((pids_len > 0) ? "POST" : "GET"), context->session_id, demux->onid, demux->tsid, demux->program_number, demux->ECMpidcount, demux->enigma_namespace, context->host_id, lenhdr); } else // no credentials configured, assume no session required { ret = snprintf((char *)req, sizeof(req), "%s /api/p/%x/%x/%x/%x/%x HTTP/1.1\r\nHost: %s%s\r\n\r\n", ((pids_len > 0) ? "POST" : "GET"), demux->onid, demux->tsid, demux->program_number, demux->ECMpidcount, demux->enigma_namespace, context->host_id, lenhdr); } } end = req + ret; if(pids_len > 0) { memcpy(end, pids, pids_len); cs_debug_mask(D_CLIENT, "%s: new unscrambling detected, switching to post", client->reader->label); _set_pid_status(context->post_contexts, demux->onid, demux->tsid, demux->program_number, 0); } cs_ddump_mask(D_CLIENT, pids, pids_len, "%s: sending capmt ecm pids - %s /api/p/%x/%x/%x/%x/%x", client->reader->label, (pids_len > 0) ? "POST" : "GET", demux->onid, demux->tsid, demux->program_number, demux->ECMpidcount, demux->enigma_namespace); ret = ghttp_send(client, req, ret + pids_len); if(pids_len > 0) { free(pids); } return 0; }
int32_t ICC_Async_Transmit (struct s_reader *reader, uint32_t size, BYTE * data) { cs_ddump_mask(D_IFD, data, size, "IFD Transmit: "); BYTE *buffer = NULL, *sent; if (reader->crdr.active==1) { if (reader->convention == ATR_CONVENTION_INVERSE && reader->crdr.need_inverse==1) { buffer = (BYTE *) calloc(sizeof (BYTE), size); memcpy (buffer, data, size); ICC_Async_InvertBuffer (size, buffer); sent = buffer; } else sent = data; call(reader->crdr.transmit(reader, sent, size)); if (buffer) free (buffer); cs_debug_mask(D_IFD, "IFD Transmit succesful"); return OK; } if (reader->convention == ATR_CONVENTION_INVERSE && reader->typ <= R_MOUSE) { buffer = (BYTE *) calloc(sizeof (BYTE), size); memcpy (buffer, data, size); ICC_Async_InvertBuffer (size, buffer); sent = buffer; } else sent = data; switch(reader->typ) { case R_MP35: case R_DB2COM1: case R_DB2COM2: case R_SC8in1: case R_MOUSE: call (Phoenix_Transmit (reader, sent, size, reader->block_delay, reader->char_delay)); break; #if defined(LIBUSB) case R_SMART: call (SR_Transmit(reader, sent, size)); break; #endif case R_INTERNAL: #if defined(COOL) call (Cool_Transmit(sent, size)); #elif defined(AZBOX) call (Azbox_Transmit(reader, sent, size)); #elif defined(SCI_DEV) call (Phoenix_Transmit (reader, sent, size, 0, 0)); //the internal reader will provide the delay #elif defined(WITH_STAPI) call (STReader_Transmit(reader->stsmart_handle, sent, size)); #endif break; default: cs_log("ERROR ICC_Async_Transmit: unknow reader type %i",reader->typ); return ERROR; } if (buffer) free (buffer); cs_debug_mask(D_IFD, "IFD Transmit succesful"); return OK; }
void do_emm(struct s_client * client, EMM_PACKET *ep) { char *typtext[]={"unknown", "unique", "shared", "global"}; char tmp[17]; int32_t emmnok=0; struct s_reader *aureader = NULL; cs_ddump_mask(D_EMM, ep->emm, ep->emmlen, "emm:"); int8_t cl_dvbapi = 0, assemble = 0; #ifdef HAVE_DVBAPI cl_dvbapi = streq(cfg.dvbapi_usr, client->account->usr); #endif if (client->account->emm_reassembly > 1 || (client->account->emm_reassembly && cl_dvbapi)) assemble = 1; LL_ITER itr = ll_iter_create(client->aureader_list); while ((aureader = ll_iter_next(&itr))) { if (!aureader->enable) continue; uint16_t caid = b2i(2, ep->caid); uint32_t provid = b2i(4, ep->provid); if (aureader->audisabled) { rdr_debug_mask(aureader, D_EMM, "AU is disabled"); /* we have to write the log for blocked EMM here because this EMM never reach the reader module where the rest of EMM log is done. */ if (aureader->logemm & 0x10) { rdr_log(aureader, "%s emmtype=%s, len=%d, idx=0, cnt=1: audisabled (0 ms)", client->account->usr, typtext[ep->type], ep->emm[2]); } continue; } if (!(aureader->grp & client->grp)) { rdr_debug_mask(aureader, D_EMM, "skip emm, group mismatch"); continue; } //TODO: provider possibly not set yet, this is done in get_emm_type() if (!emm_reader_match(aureader, caid, provid)) continue; struct s_cardsystem *cs = NULL; if (is_cascading_reader(aureader)) { // network reader (R_CAMD35 R_NEWCAMD R_CS378X R_CCCAM) if (!aureader->ph.c_send_emm) // no emm support continue; cs = get_cardsystem_by_caid(caid); if (!cs) { rdr_debug_mask(aureader, D_EMM, "unable to find cardsystem for caid %04X", caid); continue; } } else { // local reader if (aureader->csystem.active) cs=&aureader->csystem; } if (cs && cs->get_emm_type) { if (!cs->get_emm_type(ep, aureader)) { rdr_debug_mask(aureader, D_EMM, "emm skipped, get_emm_type() returns error"); emmnok++; continue; } } if (cs && cs->get_emm_filter) { if (!do_simple_emm_filter(aureader, cs, ep)) { rdr_debug_mask(aureader, D_EMM, "emm skipped, emm_filter() returns invalid"); emmnok++; continue; } } if (cs && cs->do_emm_reassembly) { if (assemble) { if (!cs->do_emm_reassembly(client, ep)) return; } else { rdr_debug_mask(aureader, D_EMM, "processing raw emm"); } } rdr_debug_mask_sensitive(aureader, D_EMM, "emmtype %s. Reader serial {%s}.", typtext[ep->type], cs_hexdump(0, aureader->hexserial, 8, tmp, sizeof(tmp))); rdr_debug_mask_sensitive(aureader, D_EMM, "emm UA/SA: {%s}.", cs_hexdump(0, ep->hexserial, 8, tmp, sizeof(tmp))); client->last = time(NULL); saveemm(aureader, ep); int32_t is_blocked = 0; switch (ep->type) { case UNKNOWN: is_blocked = (aureader->blockemm & EMM_UNKNOWN) == EMM_UNKNOWN; break; case UNIQUE : is_blocked = (aureader->blockemm & EMM_UNIQUE ) == EMM_UNIQUE; break; case SHARED : is_blocked = (aureader->blockemm & EMM_SHARED ) == EMM_SHARED; break; case GLOBAL : is_blocked = (aureader->blockemm & EMM_GLOBAL ) == EMM_GLOBAL; break; } // if not already blocked we check for block by len if (!is_blocked) is_blocked = cs_emmlen_is_blocked( aureader, ep->emm[2] ) ; if (is_blocked != 0) { #ifdef WEBIF aureader->emmblocked[ep->type]++; is_blocked = aureader->emmblocked[ep->type]; #endif /* we have to write the log for blocked EMM here because this EMM never reach the reader module where the rest of EMM log is done. */ if (aureader->logemm & 0x08) { rdr_log(aureader, "%s emmtype=%s, len=%d, idx=0, cnt=%d: blocked (0 ms)", client->account->usr, typtext[ep->type], ep->emm[2], is_blocked); } continue; } client->lastemm = time((time_t*)0); client->emmok++; if (client->account) client->account->emmok++; first_client->emmok++; //Check emmcache early: int32_t i; unsigned char md5tmp[CS_EMMSTORESIZE]; struct s_client *au_cl = aureader->client; MD5(ep->emm, ep->emm[2], md5tmp); ep->client = client; for (i=0; i<CS_EMMCACHESIZE; i++) { if (!memcmp(au_cl->emmcache[i].emmd5, md5tmp, CS_EMMSTORESIZE)) { rdr_debug_mask(aureader, D_EMM, "emm found in cache: count %d rewrite %d", au_cl->emmcache[i].count, aureader->rewritemm); if (aureader->cachemm && (au_cl->emmcache[i].count > aureader->rewritemm)) { reader_log_emm(aureader, ep, i, 2, NULL); return; } break; } } EMM_PACKET *emm_pack; if (cs_malloc(&emm_pack, sizeof(EMM_PACKET))) { rdr_debug_mask(aureader, D_EMM, "emm is being sent to reader"); memcpy(emm_pack, ep, sizeof(EMM_PACKET)); add_job(aureader->client, ACTION_READER_EMM, emm_pack, sizeof(EMM_PACKET)); } } if (emmnok > 0 && emmnok == ll_count(client->aureader_list)) { client->emmnok++; if (client->account) client->account->emmnok++; first_client->emmnok++; } }
static int32_t dre_do_emm (struct s_reader * reader, EMM_PACKET * ep) { def_resp; cs_ddump_mask(D_READER, ep->emm, ((ep->emm[1] & 0x0f) << 8) + ep->emm[2] + 3, "EMM:"); if (reader->caid == 0x4ae1) { if(ep->type == UNIQUE && ep->emm[39] == 0x3d) { /* For new package activation. */ uchar emmcmd58[26]; emmcmd58[0] = 0x58; memcpy(&emmcmd58[1], &ep->emm[40], 24); emmcmd58[25] = 0x15; if ((dre_cmd (emmcmd58))) if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; } else { uchar emmcmd52[0x3a]; emmcmd52[0] = 0x52; int32_t i; for (i = 0; i < 2; i++) { memcpy (emmcmd52 + 1, ep->emm + 5 + 32 + i * 56, 56); // check for shared address if(ep->emm[3]!=reader->sa[0][0]) return OK; // ignore, wrong address emmcmd52[0x39] = reader->provider; if ((dre_cmd (emmcmd52))) if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; //exit if response is not 90 00 } } } else { uchar emmcmd42[] = { 0x42, 0x85, 0x58, 0x01, 0xC8, 0x00, 0x00, 0x00, 0x05, 0xB8, 0x0C, 0xBD, 0x7B, 0x07, 0x04, 0xC8, 0x77, 0x31, 0x95, 0xF2, 0x30, 0xB7, 0xE9, 0xEE, 0x0F, 0x81, 0x39, 0x1C, 0x1F, 0xA9, 0x11, 0x3E, 0xE5, 0x0E, 0x8E, 0x50, 0xA4, 0x31, 0xBB, 0x01, 0x00, 0xD6, 0xAF, 0x69, 0x60, 0x04, 0x70, 0x3A, 0x91, 0x56, 0x58, 0x11 }; int32_t i; switch (ep->type) { case UNIQUE: for (i = 0; i < 2; i++) { memcpy (emmcmd42 + 1, ep->emm + 42 + i*49, 48); emmcmd42[49] = ep->emm[i*49 + 41]; //keynr emmcmd42[50] = 0x58 + ep->emm[40]; //package nr emmcmd42[51] = reader->provider; if ((dre_cmd (emmcmd42))) { if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; //exit if response is not 90 00 } } break; case SHARED: default: memcpy (emmcmd42 + 1, ep->emm + 6, 48); emmcmd42[51] = reader->provider; //emmcmd42[50] = ecmcmd42[2]; //TODO package nr could also be fixed 0x58 emmcmd42[50] = 0x58; emmcmd42[49] = ep->emm[5]; //keynr /* response: 59 05 A2 02 05 01 5B 90 00 */ if ((dre_cmd (emmcmd42))) { //first emm request if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; //exit if response is not 90 00 memcpy (emmcmd42 + 1, ep->emm + 55, 7); //TODO OR next two lines? /*memcpy (emmcmd42 + 1, ep->emm + 55, 7); //FIXME either I cant count or my EMM log contains errors memcpy (emmcmd42 + 8, ep->emm + 67, 41); */ emmcmd42[51] = reader->provider; //emmcmd42[50] = ecmcmd42[2]; //TODO package nr could also be fixed 0x58 emmcmd42[50] = 0x58; emmcmd42[49] = ep->emm[54]; //keynr if ((dre_cmd (emmcmd42))) { //second emm request if ((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) return ERROR; //exit if response is not 90 00 } } } } return OK; //success }