static int32_t camd35_recv(uchar *buf, int32_t rs) { int32_t rc = 0, s, n=0, buflen=0, len=0; for (s=0; !rc; s++) { switch(s) { case 0: if (rs < 36) { rc = -1; goto out; } break; case 1: switch (camd35_auth_client(buf)) { case 0: break; // ok case 1: rc=-2; break; // unknown user } memmove(buf, buf+4, rs-=4); break; case 2: aes_decrypt(&cl_aes_keys, buf, rs); if (rs!=boundary(4, rs)) cs_log_debug("WARNING: packet size has wrong decryption boundary"); n=(buf[0]==3) ? 0x34 : 0; //Fix for ECM request size > 255 (use ecm length field) if(buf[0]==0) buflen = (((buf[21]&0x0f)<< 8) | buf[22])+3; else buflen = buf[1]; n = boundary(4, n+20+buflen); cs_log_debug("received %d bytes from client", rs); if (n<rs) cs_log_debug("ignoring %d bytes of garbage", rs-n); else if (n>rs) rc=-3; break; case 3: if (crc32(0L, buf+20, buflen)!=b2i(4, buf+4)) rc=-4; if (!rc) rc=n; break; } } out: switch(rc) { case -2: cs_log("unknown user"); break; case -3: cs_log("incomplete request!"); break; case -4: cs_log("checksum error (wrong password?)"); break; } return(rc); }
static void camd35_process_emm(uchar *buf, int buflen) { uint32_t keysAdded = 0; uint16_t emmlen = 0; if(!buf || buflen < 23) { return; } emmlen = (((buf[21] & 0x0f) << 8) | buf[22]) + 3; if(emmlen + 20 > buflen) { return; } cs_log_debug("ProcessEMM CAID: %X", (buf[10] << 8) | buf[11]); cs_log_hexdump("ProcessEMM: ", buf+20, emmlen); if(ProcessEMM((buf[10] << 8) | buf[11], (buf[12] << 24) | (buf[13] << 16) | (buf[14] << 8) | buf[15],buf+20,&keysAdded)) { cs_log_debug("EMM nok"); } else { cs_log_debug("EMM ok"); } }
static int32_t camd35_send(uchar *buf, int32_t buflen) { int32_t l, status; unsigned char rbuf[REQ_SIZE + 15 + 4], *sbuf = rbuf + 4; //Fix ECM len > 255 if(buflen <= 0) { buflen = ((buf[0] == 0) ? (((buf[21] & 0x0f) << 8) | buf[22]) + 3 : buf[1]); } l = 20 + (((buf[0] == 3) || (buf[0] == 4)) ? 0x34 : 0) + buflen; memcpy(rbuf, cl_ucrc, 4); memcpy(sbuf, buf, l); memset(sbuf + l, 0xff, 15); // set unused space to 0xff for newer camd3's i2b_buf(4, crc32(0, sbuf + 20, buflen), sbuf + 4); l = boundary(4, l); cs_log_debug("send %d bytes to client", l); aes_encrypt_idx(&cl_aes_keys, sbuf, l); status = sendto(cl_sockfd, rbuf, l + 4, 0, (struct sockaddr *)&cl_socket, sizeof(cl_socket)); return status; }
static int32_t camd35_recv(uchar *buf, int32_t rs) { int32_t rc, s, n = 0, buflen = 0; for(rc = s = 0; !rc; s++) { switch(s) { case 0: if(rs < 36) { rc = -1; goto out; } break; case 1: switch(camd35_auth_client(buf)) { case 0: break; // ok case 1: rc = -2; break; // unknown user default: rc = -9; break; // error's from cs_auth() } memmove(buf, buf + 4, rs -= 4); break; case 2: aes_decrypt(&cl_aes_keys, buf, rs); if(rs != boundary(4, rs)) cs_log_debug("WARNING: packet size has wrong decryption boundary"); n = (buf[0] == 3) ? 0x34 : 0; //Fix for ECM request size > 255 (use ecm length field) if(buf[0] == 0) { buflen = (((buf[21] & 0x0f) << 8) | buf[22]) + 3; } else if(buf[0] == 0x3d || buf[0] == 0x3e || buf[0] == 0x3f) //cacheex-push { buflen = buf[1] | (buf[2] << 8); } else { buflen = buf[1]; } n = boundary(4, n + 20 + buflen); cs_log_debug("received %d bytes from client", rs); if(n < rs) cs_log_debug("ignoring %d bytes of garbage", rs - n); else if(n > rs) { rc = -3; } break; case 3: if(crc32(0, buf + 20, buflen) != b2i(4, buf + 4)) { rc = -4; cs_log_hexdump("camd35 checksum failed for packet: ", buf, rs); cs_log_debug("checksum: %X", b2i(4, buf+4)); } if(!rc) { rc = n; } break; } } out: if((rs > 0) && ((rc == -1) || (rc == -2))) { cs_log_debug("received %d bytes from client (native)", rs); } switch(rc) { case -1: cs_log("packet is too small (received %d bytes, expected at least 36 bytes)", rs); break; case -2: cs_log("unknown user"); break; case -3: cs_log("incomplete request !"); break; case -4: cs_log("checksum error (wrong password ?)"); break; } return (rc); }
static void camd35_process_ecm(uchar *buf, int buflen) { ECM_REQUEST er; uint16_t ecmlen = 0; if(!buf || buflen < 23) { return; } ecmlen = (((buf[21] & 0x0f) << 8) | buf[22]) + 3; if(ecmlen + 20 > buflen) { return; } memset(&er, 0, sizeof(ECM_REQUEST)); er.rc = E_UNHANDLED; er.ecmlen = ecmlen; er.srvid = b2i(2, buf + 8); er.caid = b2i(2, buf + 10); er.prid = b2i(4, buf + 12); cs_log_debug("ProcessECM CAID: %X", er.caid); cs_log_hexdump("ProcessECM: ", buf+20, ecmlen); if(ProcessECM(er.caid,buf+20,er.cw)) { er.rc = E_NOTFOUND; cs_log_debug("CW not found"); } else { er.rc = E_FOUND; cs_log_hexdump("Found CW: ", er.cw, 16); } if((er.rc == E_NOTFOUND || (er.rc == E_INVALID)) && !suppresscmd08) { buf[0] = 0x08; buf[1] = 2; memset(buf + 20, 0, buf[1]); buf[22] = er.rc; //put rc in byte 22 - hopefully don't break legacy camd3 } else if(er.rc == E_STOPPED) { buf[0] = 0x08; buf[1] = 2; buf[20] = 0; /* * the second Databyte should be forseen for a sleeptime in minutes * whoever knows the camd3 protocol related to CMD08 - please help! * on tests this don't work with native camd3 */ buf[21] = 0; cs_log("client stop request send"); } else { // Send CW if((er.rc < E_NOTFOUND) || (er.rc == E_FAKE)) { if(buf[0] == 3) { memmove(buf + 20 + 16, buf + 20 + buf[1], 0x34); } buf[0]++; buf[1] = 16; memcpy(buf + 20, er.cw, buf[1]); } else { // Send old CMD44 to prevent cascading problems with older mpcs/oscam versions buf[0] = 0x44; buf[1] = 0; } } camd35_send(buf, 0); }