revert breaks some stupid old compilers
[oscam.git] / module-scam.c
blob72476581d6b3dd92c1d122cf9c0d29d1649423eb
1 #define MODULE_LOG_PREFIX "scam"
3 #include "globals.h"
4 #ifdef MODULE_SCAM
5 #include "oscam-client.h"
6 #include "oscam-ecm.h"
7 #include "oscam-net.h"
8 #include "oscam-string.h"
9 #include "oscam-reader.h"
10 #include "oscam-lock.h"
11 #include "oscam-time.h"
12 #include "oscam-chk.h"
13 #include "cscrypt/des.h"
15 struct scam_data
17 uchar enckey[8];
18 uchar deckey[8];
19 uint8_t enc_xor_offset;
20 uint8_t dec_xor_offset;
21 uint8_t login_pending;
22 char login_username[64];
23 uint16_t version;
26 static inline void xxor(uint8_t *data, int32_t len, const uint8_t *v1, const uint8_t *v2)
28 uint32_t i;
29 switch(len)
31 case 16:
32 for(i = 8; i < 16; ++i)
34 data[i] = v1[i] ^ v2[i];
36 case 8:
37 for(i = 4; i < 8; ++i)
39 data[i] = v1[i] ^ v2[i];
41 case 4:
42 for(i = 0; i < 4; ++i)
44 data[i] = v1[i] ^ v2[i];
46 break;
47 default:
48 while(len--) { *data++ = *v1++ ^ *v2++; }
49 break;
53 static void scam_generate_deskey(char *keyString, uint8_t *desKey)
55 uint8_t iv[8], *tmpKey;
56 int32_t i, passLen, alignedPassLen;
57 uint32_t key_schedule[32];
59 memset(iv, 0, 8);
60 memset(desKey, 0, 8);
62 passLen = keyString == NULL ? 0 : strlen(keyString);
63 if(passLen > 1024) {
64 passLen = 1024;
67 alignedPassLen = (passLen + 7) & -8;
68 if(alignedPassLen == 0) alignedPassLen = 8;
70 if(!cs_malloc(&tmpKey, alignedPassLen)) {
71 return;
74 if(passLen == 0) {
75 memset(tmpKey, 0xAA, 8);
76 passLen = 8;
78 else {
79 memcpy(tmpKey, keyString, passLen);
82 for(i=0; i<alignedPassLen-passLen; i++) {
83 tmpKey[passLen+i] = (uint8_t)i;
86 xxor(desKey,8,tmpKey,iv);
88 for(i=0; i<alignedPassLen; i+=8) {
89 des_set_key(&tmpKey[i], key_schedule);
90 des(&tmpKey[i], key_schedule, 1);
91 xxor(desKey,8,desKey,&tmpKey[i]);
94 NULLFREE(tmpKey);
97 static void scam_encrypt_packet(uint8_t *packet, uint32_t packetLength, uint8_t *key, uint32_t dataLength, uint32_t dataOffset, uint8_t *xorOffset)
99 uint8_t iv[8];
100 uint32_t i;
101 memset(iv, 0, 8);
103 des_cbc_encrypt(packet + dataOffset, iv, key, dataLength);
105 for(i=0; i<packetLength; i++) {
106 key[*xorOffset] ^= packet[i];
107 *xorOffset = (*xorOffset + 1) & 7;
111 static void scam_decrypt_packet(uint8_t *packet, uint32_t packetLength, uint8_t *key, uint32_t dataLength, uint32_t dataOffset, uint8_t *xorOffset)
113 uint8_t tmpKey[8], iv[8];
114 uint32_t i;
115 memcpy(tmpKey, key, 8);
116 memset(iv, 0, 8);
118 for(i=0; i<packetLength; i++) {
119 tmpKey[*xorOffset] ^= packet[i];
120 *xorOffset = (*xorOffset + 1) & 7;
123 des_cbc_decrypt(packet + dataOffset, iv, key, dataLength);
124 memcpy(key, tmpKey, 8);
127 static void scam_decode_length(uint8_t *packet, uint32_t *dataLength, uint32_t *dataOffset)
129 uint32_t i, n;
131 if(packet[1] & 0x80) {
132 n = packet[1]&~0x80;
133 *dataLength = 0;
134 for(i=0; i<n; i++) {
135 *dataLength = (*dataLength << 8) | packet[2+i];
137 *dataOffset = 2 + n;
139 else {
140 *dataLength = packet[1];
141 *dataOffset = 2;
145 static uint32_t scam_get_length_data_length(uint8_t *packet)
147 if(packet[1] & 0x80) {
148 return packet[1]&~0x80;
150 else {
151 return 1;
155 static void scam_encode_length(uint32_t len, uint8_t *data, uint8_t *dataLen)
157 if(len < 128)
159 data[0] = (uint8_t)len;
160 *dataLen = 1;
162 else if (len < 256 )
164 data[0] = 0x81;
165 data[1] = (uint8_t)len;
166 *dataLen = 2;
168 else if (len < 65536 ) {
169 data[0] = 0x82;
170 data[1] = (uint8_t)(len>>8);
171 data[2] = (uint8_t)(len&0xFF);
172 *dataLen = 3;
174 else if (len < 16777216 )
176 data[0] = 0x83;
177 data[1] = (uint8_t)(len>>16);
178 data[2] = (uint8_t)((len>>8)&0xFF);
179 data[3] = (uint8_t)(len&0xFF);
180 *dataLen = 4;
182 else
184 data[0] = 0x84;
185 data[1] = (uint8_t)(len>>24);
186 data[2] = (uint8_t)((len>>16)&0xFF);
187 data[3] = (uint8_t)((len>>8)&0xFF);
188 data[4] = (uint8_t)(len&0xFF);
189 *dataLen = 5;
194 static void scam_client_close(struct s_client *cl, int32_t call_conclose)
196 struct s_reader *rdr = cl->reader;
197 if(!rdr) { return; }
199 if(rdr) { rdr->tcp_connected = 0; }
200 if(rdr) { rdr->card_status = NO_CARD; }
201 if(rdr) { rdr->last_s = rdr->last_g = 0; }
202 if(cl) { cl->last = 0; }
204 if(call_conclose) //clears also pending ecms!
205 { network_tcp_connection_close(rdr, "close"); }
206 else
208 if(cl->udp_fd)
210 close(cl->udp_fd);
211 cl->udp_fd = 0;
212 cl->pfd = 0;
217 static int32_t scam_send(struct s_client *cl, uchar *buf, uint32_t len)
219 uchar *mbuf, lenData[5];
220 uint8_t lenDataLen = 0, paddingLen = 0;
221 uint16_t crc = 0;
222 int32_t result, packetLen;
223 struct scam_data *scam = cl->scam;
225 if(scam == NULL) { return 0; }
226 if(len == 0) { return 0; }
228 paddingLen = 8 - ((4+len) % 8);
229 if(paddingLen == 8) {
230 paddingLen = 0;
232 else if(paddingLen > 0 && paddingLen < 3) {
233 paddingLen += 8;
236 scam_encode_length(4+len+paddingLen, lenData, &lenDataLen);
237 if(lenDataLen == 0) { return -1; }
238 packetLen = 1+lenDataLen+4+len+paddingLen;
239 if(!cs_malloc(&mbuf, packetLen)) { return -1; }
241 mbuf[0] = 0x0F;
242 memcpy(&mbuf[1], lenData, lenDataLen);
243 mbuf[1+lenDataLen] = 0x10;
244 mbuf[1+lenDataLen+1] = 0x02;
245 memcpy(&mbuf[1+lenDataLen+4], buf, len);
247 if(paddingLen > 0) {
248 mbuf[1+lenDataLen+4+len] = 0x7F;
249 mbuf[1+lenDataLen+4+len+1] = paddingLen - 2;
250 get_random_bytes(mbuf+1+lenDataLen+4+len+2, paddingLen - 2);
253 crc = ccitt_crc(mbuf+1+lenDataLen+4, len+paddingLen, 0xFFFF, 0);
254 i2b_buf(2, crc, &mbuf[1+lenDataLen+2]);
256 scam_encrypt_packet(mbuf, packetLen, scam->enckey, 4+len+paddingLen, 1+lenDataLen, &scam->enc_xor_offset);
257 result = send(cl->pfd, mbuf, packetLen, 0);
258 NULLFREE(mbuf);
260 return (result);
263 static int32_t scam_msg_recv(struct s_client *cl, uint8_t *buf, int32_t maxlen)
265 int32_t len;
266 int32_t handle = cl->udp_fd;
267 struct scam_data *scam = cl->scam;
269 if(scam == NULL) { return 0; }
270 if(handle <= 0 || maxlen < 3)
271 { cs_log("scam_msg_recv: fd is 0"); return -1; }
273 len = cs_recv(handle, buf, 2, MSG_WAITALL);
274 if(len != 2) // invalid header length read
276 if(len <= 0)
277 { cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "disconnected by remote server"); }
278 else
279 { cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "invalid header length (expected 2, read %d)", len); }
280 return -1;
283 if(buf[0] != 0x0F)
285 cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "invalid packet tag");
286 return 0;
289 int32_t headerSize = buf[1]&0x80 ? (2 + (buf[1]&~0x80)) : 2;
290 if(headerSize > 2) {
291 if(maxlen < headerSize+1) { return -1; }
292 len = cs_recv(handle, buf+2, headerSize-2, MSG_WAITALL);
293 if(len != headerSize-2) // invalid header length read
295 if(len <= 0)
296 { cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "disconnected by remote server"); }
297 else
298 { cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "invalid header length (expected %d, read %d)", headerSize, 2+len); }
299 return -1;
303 uint32_t dataLength, dataOffset;
304 scam_decode_length(buf, &dataLength, &dataOffset);
306 if(dataLength) // check if any data is expected in msg
308 if(dataLength%8 != 0)
310 cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "message data has invalid size (size=%d)", dataLength);
311 return 0;
314 if(headerSize+dataLength > (uint32_t)maxlen)
316 cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "message too big (size=%d max=%d)", headerSize+dataLength, maxlen);
317 return 0;
320 len = cs_recv(handle, buf + dataOffset, dataLength, MSG_WAITALL);
321 if((uint32_t)len != dataLength)
323 if(len <= 0) {
324 cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "disconnected by remote");
326 else {
327 cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "invalid message length read (expected %d, read %d)", dataLength, len);
329 return -1;
332 scam_decrypt_packet(buf, headerSize+dataLength, scam->deckey, dataLength, dataOffset, &scam->dec_xor_offset);
335 return headerSize+dataLength;
338 static int32_t scam_recv(struct s_client *cl, uchar *buf, int32_t len)
340 int32_t n;
341 struct s_reader *rdr = (cl->typ == 'c') ? NULL : cl->reader;
343 if(buf == NULL || len <= 0)
344 { return -1; }
346 n = scam_msg_recv(cl, buf, len); // recv and decrypt msg
347 if(n <= 0)
349 cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "connection closed by %s, n=%d.", remote_txt(), n);
350 if(rdr)
352 scam_client_close(cl, 1);
354 else
356 cs_disconnect_client(cl);
358 cs_sleepms(150);
359 n = -1;
361 else
363 cl->last = time(NULL); // last client action is now
364 if(rdr) { rdr->last_g = time(NULL); } // last reader receive is now
367 return n;
370 //scam client functions
372 static int32_t scam_client_init(struct s_client *cl);
374 static int32_t scam_client_connect(void)
376 struct s_client *cl = cur_client();
378 if(cl->reader->tcp_connected < 2 && scam_client_init(cl) < 0)
379 { return 0; }
381 if(!cl->udp_fd)
382 { return 0; }
384 return 1;
387 static void scam_client_idle(void)
389 struct s_client *client = cur_client();
390 struct s_reader *rdr = client->reader;
391 time_t now = time(NULL);
392 if(!rdr) { return; }
394 if(rdr->tcp_ito > 0)
396 int32_t time_diff;
397 time_diff = llabs(now - rdr->last_s);
398 if(time_diff > (rdr->tcp_ito))
400 network_tcp_connection_close(rdr, "inactivity");
401 return;
404 else if(rdr->tcp_ito == -1)
406 scam_client_connect();
407 return;
411 static void scam_client_recv_caid(uint8_t *buf, uint32_t len)
413 uint16_t caid;
415 if(len < 3) {
416 return;
419 caid = buf[1] << 8 | buf[2];
420 if(buf[0]) {
421 cs_log("scam server has card: %04X", caid);
423 else {
424 cs_log("scam server no longer has card: %04X", caid);
428 static void scam_client_recv_server_version(uint8_t *buf, uint32_t len)
430 uint32_t pos = 0, dataLength = 0, dataOffset = 0, usedLen = 0;
431 char versionString[128];
432 uint16_t versionShort = 0;
433 versionString[0] = 0;
435 scam_decode_length(buf, &dataLength, &dataOffset);
437 while(pos+dataOffset+dataLength-1 < len)
439 switch(buf[pos]) {
441 case 0x01: // version string
442 usedLen = dataLength;
443 if(usedLen > 127) {
444 usedLen = 127;
446 memcpy(versionString, buf+dataOffset, usedLen);
447 versionString[usedLen] = 0;
448 break;
450 case 0x0A: // version short
451 if(dataLength != 2) break;
452 versionShort = (buf[pos+dataOffset] << 8) | buf[pos+dataOffset+1];
453 break;
455 default:
456 cs_log_dbg(D_READER, "unknown server version packet tag %X", buf[pos]);
457 break;
460 pos += dataOffset+dataLength;
461 if(pos+2 < len && pos+1+scam_get_length_data_length(buf+pos) < len) {
462 scam_decode_length(buf+pos, &dataLength, &dataOffset);
464 else {
465 break;
469 cs_log("scam server version: %s (%d)", versionString, versionShort);
472 static void scam_client_recv_dcw(struct s_client *cl, uint8_t *buf, uint32_t len, uint8_t *dcw, int32_t *ecm_task_idx, int32_t *rc)
474 // 00C00000 enimga namespace
475 // 0455 tsid
476 // 0001 onid
477 // 151A srvid
478 // 200081 ???
479 // 943E85577035C469 dcw1
480 // C73882811721E31B dcw2
482 if(len != 29) {
483 cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "unknown server dcw packet length %d", len);
484 return;
487 *ecm_task_idx = b2i(4, &buf[0]); // we store idx here instead of ens
488 memcpy(dcw, &buf[13], 16);
489 *rc = 1;
492 static void scam_client_send_hello(struct s_client *cl)
494 uchar mbuf[70];
495 uint32_t usernameLen, i = 0;
496 struct s_reader *rdr = cl->reader;
497 struct scam_data *scam = cl->scam;
499 if(scam == NULL) { return; }
500 if(!rdr) { return; }
502 usernameLen = strlen(rdr->r_usr);
503 if(usernameLen > 63) { // because rdr->r_usr is max. 63+1 chars
504 usernameLen = 63;
507 mbuf[i++] = 0x46; // client hello data type
508 mbuf[i++] = 6 + usernameLen; // will never exceed 63+6 = 69 bytes (<127 bytes)
510 // client version
511 mbuf[i++] = 0xA0; // client version data type
512 mbuf[i++] = 0x02; // data length (2)
513 mbuf[i++] = 0x00; // version ( 0x0007)
514 mbuf[i++] = 0x07;
516 //username
517 mbuf[i++] = 0xA1; // username data type
518 mbuf[i++] = (uint8_t)usernameLen;
519 memcpy(mbuf+i, rdr->r_usr, usernameLen);
520 mbuf[i+usernameLen] = 0;
522 scam_send(cl, mbuf, 8+usernameLen);
524 scam_generate_deskey(rdr->r_pwd, scam->enckey);
525 scam_generate_deskey(rdr->r_pwd, scam->deckey);
526 scam->enc_xor_offset = 0;
527 scam->dec_xor_offset = 0;
530 static int32_t scam_client_send_ecm(struct s_client *cl, ECM_REQUEST *er)
532 // 2481A5 310A
533 // 00C00000 enimga namespace
534 // 0455 tsid
535 // 0001 onid
536 // 151A srvid
537 // 3002
538 // 1843 caid
539 // 3304
540 // 66A1AE16 pat/pmt crc? we currently fill it with chid
541 // 348189
542 // 8130.. ecm
543 // 3501
544 // 02 needed dcws?
546 uchar *mbuf, packetLenData[5], ecmLenData[5];
547 uint32_t i = 0, ret = 0, dataLength = 0, packetLength = 0;
548 uint8_t pLenDataLen = 0, eLenDataLen = 0;
550 if(!scam_client_connect())
551 { return (-1); }
553 scam_encode_length(er->ecmlen, ecmLenData, &eLenDataLen);
554 dataLength = 23 + eLenDataLen + er->ecmlen + 3;
555 scam_encode_length(dataLength, packetLenData, &pLenDataLen);
556 packetLength = 1 + pLenDataLen + dataLength;
558 if(!cs_malloc(&mbuf, packetLength))
559 { return -1; }
561 mbuf[i++] = 0x24; // ecm request data type
562 memcpy(mbuf+i, packetLenData, pLenDataLen); i += pLenDataLen;
564 mbuf[i++] = 0x31; // channel info data type
565 mbuf[i++] = 0x0A; // size is always 0x0A
567 //i2b_buf(4, er->ens, mbuf+i); i += 4;
568 i2b_buf(4, er->idx, mbuf+i); i += 4; // we store idx instead of ens here
570 i2b_buf(2, er->tsid, mbuf+i); i += 2;
571 i2b_buf(2, er->onid, mbuf+i); i += 2;
572 i2b_buf(2, er->srvid, mbuf+i); i += 2;
574 mbuf[i++] = 0x30; // caid data type
575 mbuf[i++] = 0x02; // size is always 0x02
576 i2b_buf(2, er->caid, mbuf+i); i += 2;
578 mbuf[i++] = 0x33; // ??? data type
579 mbuf[i++] = 0x04; // size is always 0x04
580 i2b_buf(2, er->chid, mbuf+i); i += 4;
582 mbuf[i++] = 0x34; // ecm data type
583 memcpy(mbuf+i, ecmLenData, eLenDataLen); i += eLenDataLen;
584 memcpy(mbuf+i, er->ecm, er->ecmlen); i += er->ecmlen;
586 mbuf[i++] = 0x35; // ??? data type
587 mbuf[i++] = 0x01; // size is always 0x01
588 mbuf[i++] = 0x02; // unknown value
590 ret = scam_send(cl, mbuf, packetLength);
592 cs_log_dbg(D_TRACE, "scam: sending ecm");
593 cs_log_dump_dbg(D_CLIENT, mbuf, packetLength, "ecm:");
594 NULLFREE(mbuf);
595 return ((ret < 1) ? (-1) : 0);
598 static int32_t scam_client_init(struct s_client *cl)
600 int32_t handle;
602 handle = network_tcp_connection_open(cl->reader);
603 if(handle < 0) {
604 cl->reader->last_s = 0; // set last send to zero
605 cl->reader->last_g = 0; // set last receive to zero
606 cl->last = 0; // set last client action to zero
607 return (0);
610 if(cl->scam) {
611 memset(cl->scam, 0, sizeof(struct scam_data));
614 if(!cl->scam && !cs_malloc(&cl->scam, sizeof(struct scam_data))) {
615 return 0;
618 cs_log("scam: proxy %s:%d (fd=%d)",
619 cl->reader->device, cl->reader->r_port, cl->udp_fd);
621 cl->reader->tcp_connected = 2;
622 cl->reader->card_status = CARD_INSERTED;
623 cl->reader->last_g = cl->reader->last_s = time((time_t *)0);
625 cs_log_dbg(D_CLIENT, "scam: last_s=%ld, last_g=%ld", cl->reader->last_s, cl->reader->last_g);
627 cl->pfd = cl->udp_fd;
629 scam_client_send_hello(cl);
631 return (0);
634 static int32_t scam_client_handle(struct s_client *cl, uchar *dcw, int32_t *rc, uchar *buf, int32_t n)
636 uint32_t pos = 0, packetLength = 0, packetOffset = 0, dataLength = 0, dataOffset = 0;
637 int32_t ret = -1;
639 if(n < 3) {
640 return (-1);
643 scam_decode_length(buf, &packetLength, &packetOffset);
644 pos += packetOffset;
646 if(pos+2 < (uint32_t)n && pos+1+scam_get_length_data_length(buf+pos) < (uint32_t)n) {
647 scam_decode_length(buf+pos, &dataLength, &dataOffset);
649 else {
650 return (-1);
653 while(pos+dataOffset+dataLength-1 < (uint32_t)n)
655 switch(buf[pos]) {
656 case 0x10: // checksum
657 if(dataLength != 2) { break; }
658 if(b2i(2, &buf[pos+dataOffset]) != ccitt_crc(buf+pos+dataOffset+2, n-pos-dataOffset-2, 0xFFFF, 0)) {
659 cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "sent packet with invalid checksum");
660 return (-1);
662 break;
664 case 0x20: // caid list
665 scam_client_recv_caid(buf+pos+dataOffset, dataLength);
666 break;
668 case 0x45: // server version
669 scam_client_recv_server_version(buf+pos+dataOffset, dataLength);
670 break;
672 case 0x63: // dcw
673 scam_client_recv_dcw(cl, buf+pos+dataOffset, dataLength, dcw, &ret, rc);
674 break;
676 case 0x7F: // padding
677 break;
679 default:
680 cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "unknown scam server packet %X", buf[pos]);
681 break;
684 pos += dataOffset+dataLength;
685 if(pos+2 < (uint32_t)n && pos+1+scam_get_length_data_length(buf+pos) < (uint32_t)n) {
686 scam_decode_length(buf+pos, &dataLength, &dataOffset);
688 else {
689 break;
693 return ret;
696 // scam server functions
697 static uint8_t scam_server_authip_client(struct s_client *cl)
699 if(cfg.scam_allowed && !check_ip(cfg.scam_allowed, cl->ip))
701 cs_log("scam: IP not allowed");
702 cs_auth_client(cl, (struct s_auth *)0, NULL);
703 cs_disconnect_client(cl);
704 return 0;
707 return 1;
710 static void scam_server_init(struct s_client *cl)
712 if(!cl->init_done)
714 if(IP_ISSET(cl->ip))
715 { cs_log("scam: new connection from %s", cs_inet_ntoa(cl->ip)); }
717 if(scam_server_authip_client(cl)) {
718 if(cl->scam) {
719 memset(cl->scam, 0, sizeof(struct scam_data));
721 if(cl->scam || cs_malloc(&cl->scam, sizeof(struct scam_data))) {
722 cl->init_done = 1;
726 return;
729 static void scam_server_recv_ecm(struct s_client *cl, uchar *buf, int32_t len)
731 uint32_t pos = 0, dataLength = 0, dataOffset = 0, usedLen = 0;
732 ECM_REQUEST *er;
733 uint8_t gotCaid = 0, gotEcm = 0;
735 if(len < 1) {
736 return;
739 if(!(er = get_ecmtask()))
740 { return; }
742 scam_decode_length(buf, &dataLength, &dataOffset);
744 while(pos+dataOffset+dataLength-1 < (uint32_t)len)
746 switch(buf[pos]) {
748 case 0x31: // channel data
749 if(dataLength != 0x0A) break;
750 er->ens = b2i(4, buf+pos+dataOffset);
751 er->tsid = b2i(2, buf+pos+dataOffset+4);
752 er->onid = b2i(2, buf+pos+dataOffset+6);
753 er->srvid = b2i(2, buf+pos+dataOffset+8);
754 break;
756 case 0x30: // caid
757 if(dataLength != 0x02) break;
758 er->caid = b2i(2, buf+pos+dataOffset);
759 gotCaid = 1;
760 break;
762 case 0x33: // unknown
763 break;
765 case 0x34: // ecm
766 usedLen = dataLength;
767 if(usedLen > MAX_ECM_SIZE) {
768 break;
770 er->ecmlen = usedLen;
771 memcpy(er->ecm, buf+pos+dataOffset, usedLen);
772 gotEcm = 1;
773 break;
775 case 0x35: // unknown
776 break;
778 default:
779 cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "sent unknown scam client ecm tag %X", buf[pos]);
780 break;
783 pos += dataOffset+dataLength;
784 if(pos+2 < (uint32_t)len && pos+1+scam_get_length_data_length(buf+pos) < (uint32_t)len) {
785 scam_decode_length(buf+pos, &dataLength, &dataOffset);
787 else {
788 break;
792 if(gotCaid && gotEcm) {
793 get_cw(cl, er);
795 else {
796 NULLFREE(er);
797 cs_log("WARNING: ECM-request corrupt");
801 static void scam_caidlist_add(uint16_t *caidlist, uint32_t listsize, uint32_t *count, uint16_t caid)
803 uint32_t i;
804 uint8_t exists = 0;
806 if(*count >= listsize) {
807 return;
810 for(i=0; i<*count; i++) {
811 if(caidlist[i] == caid) {
812 exists = 1;
813 break;
817 if(!exists) {
818 caidlist[*count] = caid;
819 (*count)++;
823 static void scam_server_send_caidlist(struct s_client *cl)
825 uchar mbuf[5];
826 int32_t j;
827 uint32_t i = 0;
828 uint16_t caids[55];
829 uint32_t cardcount = 0;
830 struct s_reader *rdr = NULL;
832 cs_readlock(__func__, &readerlist_lock);
833 for(rdr = first_active_reader; rdr; rdr = rdr->next)
835 if(rdr->caid && chk_ctab(rdr->caid, &cl->ctab)) {
836 scam_caidlist_add(caids, ARRAY_SIZE(caids), &cardcount, rdr->caid);
839 for(j = 0; j < rdr->ctab.ctnum; j++) {
840 CAIDTAB_DATA *d = &rdr->ctab.ctdata[j];
841 if(d->caid && chk_ctab(d->caid, &cl->ctab)) {
842 scam_caidlist_add(caids, ARRAY_SIZE(caids), &cardcount, d->caid);
846 cs_readunlock(__func__, &readerlist_lock);
848 for(j=0; j < (int32_t)cardcount; j++) {
849 i = 0;
850 mbuf[i++] = 0x20; // caid data type
851 mbuf[i++] = 0x03; // length
852 mbuf[i++] = 0x01; // active card
853 i2b_buf(2, caids[j], mbuf+i);
854 scam_send(cl, mbuf, 5);
858 static void scam_server_send_serverversion(struct s_client *cl)
860 uchar mbuf[64];
861 uint32_t i = 0;
862 char *version = "scam/3.60 oscam";
863 uint8_t vlen = strlen(version);
865 mbuf[i++] = 0x45; // server version data type
866 mbuf[i++] = 2+vlen+4; // will never exceed 127 bytes
868 mbuf[i++] = 0x01; // server version string data type
869 mbuf[i++] = vlen; // will never exceed 127 bytes
870 memcpy(mbuf+i, version, vlen); i += vlen;
872 mbuf[i++] = 0x0A; // server version short data type
873 mbuf[i++] = 0x02; // is always 0x02
874 i2b_buf(2, 0x7, mbuf+i);
876 scam_send(cl, mbuf, 2+2+vlen+4);
879 static void scam_server_recv_auth(struct s_client *cl, uchar *buf, int32_t len)
881 uint32_t pos = 0, dataLength = 0, dataOffset = 0, usedLen = 0;
882 uint8_t userok = 0;
883 struct s_auth *account;
884 struct scam_data *scam = cl->scam;
886 if(scam == NULL) { return; }
887 scam->login_username[0] = 0;
889 if(len < 1) {
890 return;
893 scam_decode_length(buf, &dataLength, &dataOffset);
895 while(pos+dataOffset+dataLength-1 < (uint32_t)len)
897 switch(buf[pos]) {
899 case 0xA0: // version short
900 if(dataLength != 2) break;
901 scam->version = (buf[pos+dataOffset] << 8) | buf[pos+dataOffset+1];
902 break;
904 case 0xA1: // username string
905 usedLen = dataLength;
906 if(usedLen > 64) {
907 usedLen = 63;
909 memcpy(scam->login_username, buf+pos+dataOffset, usedLen);
910 scam->login_username[usedLen] = 0;
911 break;
913 default:
914 cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "unknown client auth packet tag %X", buf[pos]);
915 break;
918 pos += dataOffset+dataLength;
919 if(pos+2 < (uint32_t)len && pos+1+scam_get_length_data_length(buf+pos) < (uint32_t)len) {
920 scam_decode_length(buf+pos, &dataLength, &dataOffset);
922 else {
923 break;
927 for(account = cfg.account; account; account = account->next)
929 if(streq(scam->login_username, account->usr))
931 userok = 1;
932 break;
936 if(!userok)
938 cs_auth_client(cl, (struct s_auth *)0, NULL);
939 cs_disconnect_client(cl);
940 return;
943 scam->login_pending = 1;
944 scam_generate_deskey(account->pwd, scam->enckey);
945 scam_generate_deskey(account->pwd, scam->deckey);
946 scam->enc_xor_offset = 0;
947 scam->dec_xor_offset = 0;
949 scam_server_send_caidlist(cl);
950 scam_server_send_serverversion(cl);
953 static void scam_server_send_dcw(struct s_client *cl, ECM_REQUEST *er)
955 uchar mbuf[31];
956 uint32_t i = 0;
958 if(!(er->rc < E_NOTFOUND)) {
959 return;
962 mbuf[i++] = 0x63; // dcw data type
963 mbuf[i++] = 0x1D; // fixed sized < 127
965 i2b_buf(4, er->ens, mbuf+i); i += 4;
966 i2b_buf(2, er->tsid, mbuf+i); i += 2;
967 i2b_buf(2, er->onid, mbuf+i); i += 2;
968 i2b_buf(2, er->srvid, mbuf+i); i += 2;
970 mbuf[i++] = 0x20; // unknown
971 mbuf[i++] = 0x00; // unknown
972 mbuf[i++] = 0x81; // unknown
973 memcpy(mbuf+i, er->cw, 16);
975 scam_send(cl, mbuf, 31);
978 static void *scam_server_handle(struct s_client *cl, uchar *buf, int32_t n)
980 uint32_t pos = 0, packetLength = 0, packetOffset = 0, dataLength = 0, dataOffset = 0;
981 struct s_auth *account;
982 struct scam_data *scam;
984 if(n < 3)
985 { return NULL; }
987 if(!cl->init_done)
989 if(!scam_server_authip_client(cl)) { return NULL; }
990 if(cl->scam) {
991 memset(cl->scam, 0, sizeof(struct scam_data));
993 if(cl->scam == NULL && !cs_malloc(&cl->scam, sizeof(struct scam_data))) {
994 return NULL;
996 cl->init_done = 1;
999 scam = cl->scam;
1000 if(scam == NULL) {
1001 return NULL;
1004 scam_decode_length(buf, &packetLength, &packetOffset);
1005 pos += packetOffset;
1007 if(scam->login_pending && packetLength > 1 && (buf[pos] != 0x10 || buf[pos+1] != 0x02)) {
1008 scam->login_pending = 0;
1009 cs_auth_client(cl, (struct s_auth *)0, NULL);
1010 cs_disconnect_client(cl);
1011 return NULL;
1014 if(pos+2 < (uint32_t)n && pos+1+scam_get_length_data_length(buf+pos) < (uint32_t)n) {
1015 scam_decode_length(buf+pos, &dataLength, &dataOffset);
1017 else {
1018 return NULL;
1021 while(pos+dataOffset+dataLength-1 < (uint32_t)n)
1023 switch(buf[pos]) {
1025 case 0x10: // checksum
1026 if(dataLength != 2) { break; }
1027 if(b2i(2, &buf[pos+dataOffset]) != ccitt_crc(buf+pos+dataOffset+2, n-pos-dataOffset-2, 0xFFFF, 0)) {
1028 cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "sent packet with invalid checksum");
1029 return NULL;
1031 if(scam->login_pending) {
1032 for(account = cfg.account; account; account = account->next) {
1033 if(streq(scam->login_username, account->usr)) {
1034 scam->login_pending = 0;
1035 if(!cs_auth_client(cl, account, NULL)) {
1036 cs_log("scam client login: %s version: %d", scam->login_username, scam->version);
1038 else {
1039 cs_disconnect_client(cl);
1041 break;
1044 if(scam->login_pending)
1046 scam->login_pending = 0;
1047 cs_auth_client(cl, (struct s_auth *)0, NULL);
1048 cs_disconnect_client(cl);
1049 return NULL;
1052 break;
1054 case 0x46: // client auth
1055 scam_server_recv_auth(cl, buf+pos+dataOffset, dataLength);
1056 break;
1058 case 0x24: // ecm request
1059 scam_server_recv_ecm(cl, buf+pos+dataOffset, dataLength);
1060 break;
1062 case 0x7F: // padding
1063 break;
1065 default:
1066 cs_log_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, "sent unknown scam client packet %X", buf[pos]);
1067 break;
1070 pos += dataOffset+dataLength;
1071 if(pos+2 < (uint32_t)n && pos+1+scam_get_length_data_length(buf+pos) < (uint32_t)n) {
1072 scam_decode_length(buf+pos, &dataLength, &dataOffset);
1074 else {
1075 break;
1079 return NULL;
1082 void scam_cleanup(struct s_client *cl)
1084 NULLFREE(cl->scam);
1087 void module_scam(struct s_module *ph)
1089 ph->desc = "scam";
1090 ph->type = MOD_CONN_TCP;
1091 ph->listenertype = LIS_SCAM;
1092 ph->num = R_SCAM;
1093 ph->large_ecm_support = 1;
1094 IP_ASSIGN(ph->s_ip, cfg.scam_srvip);
1095 ph->ptab.nports = 1;
1096 ph->ptab.ports[0].s_port = cfg.scam_port;
1097 // server + client
1098 ph->recv = scam_recv;
1099 ph->cleanup = scam_cleanup;
1100 // server
1101 ph->s_init = scam_server_init;
1102 ph->s_handler = scam_server_handle;
1103 ph->send_dcw = scam_server_send_dcw;
1104 // client
1105 ph->c_init = scam_client_init;
1106 ph->c_idle = scam_client_idle;
1107 ph->c_recv_chk = scam_client_handle;
1108 ph->c_send_ecm = scam_client_send_ecm;
1111 #endif