source: trunk/module-camd35.c@ 1770

Last change on this file since 1770 was 1770, checked in by landlord, 10 years ago

Removed dummy hexserial variables, not needed anymore.

File size: 14.8 KB
Line 
1#include "globals.h"
2
3//CMD00 - ECM (request)
4//CMD01 - ECM (response)
5//CMD02 - EMM (in clientmode - set EMM, in server mode - EMM data) - obsolete
6//CMD03 - ECM (cascading request)
7//CMD04 - ECM (cascading response)
8//CMD05 - EMM (emm request) send cardata/cardinfo to client
9//CMD06 - EMM (incomming EMM in server mode)
10//CMD19 - EMM (incomming EMM in server mode) only seen with caid 0x1830
11//CMD08 - Stop sending requests to the server for current srvid,prvid,caid
12//CMD44 - MPCS/OScam internal error notification
13
14#define REQ_SIZE 328 // 256 + 20 + 0x34
15static uchar upwd[64]={0};
16static uchar *req;
17static int is_udp=1;
18
19static int camd35_send(uchar *buf)
20{
21 int l;
22 unsigned char rbuf[REQ_SIZE+15+4], *sbuf=rbuf+4;
23
24 if (!client[cs_idx].udp_fd) return(-1);
25 l=20+buf[1]+(((buf[0]==3) || (buf[0]==4)) ? 0x34 : 0);
26 memcpy(rbuf, client[cs_idx].ucrc, 4);
27 memcpy(sbuf, buf, l);
28 memset(sbuf+l, 0xff, 15); // set unused space to 0xff for newer camd3's
29 memcpy(sbuf+4, i2b(4, crc32(0L, sbuf+20, sbuf[1])), 4);
30 l=boundary(4, l);
31 cs_ddump(sbuf, l, "send %d bytes to %s", l, remote_txt());
32 aes_encrypt(sbuf, l);
33
34 if (is_udp)
35 return(sendto(client[cs_idx].udp_fd, rbuf, l+4, 0,
36 (struct sockaddr *)&client[cs_idx].udp_sa,
37 sizeof(client[cs_idx].udp_sa)));
38 else
39 return(send(client[cs_idx].udp_fd, rbuf, l+4, 0));
40}
41
42static int camd35_auth_client(uchar *ucrc)
43{
44 int rc=1;
45 ulong crc;
46 struct s_auth *account;
47
48 if (upwd[0])
49 return(memcmp(client[cs_idx].ucrc, ucrc, 4) ? 1 : 0);
50 client[cs_idx].crypted=1;
51 crc=(((ucrc[0]<<24) | (ucrc[1]<<16) | (ucrc[2]<<8) | ucrc[3]) & 0xffffffffL);
52 for (account=cfg->account; (account) && (!upwd[0]); account=account->next)
53 if (crc==crc32(0L, MD5((unsigned char *)account->usr, strlen(account->usr), NULL), 16))
54 {
55 memcpy(client[cs_idx].ucrc, ucrc, 4);
56 strcpy((char *)upwd, account->pwd);
57 aes_set_key((char *) MD5(upwd, strlen((char *)upwd), NULL));
58 rc=cs_auth_client(account, NULL);
59 }
60 return(rc);
61}
62
63static int camd35_recv(uchar *buf, int l)
64{
65 int rc, s, rs, n=0;
66 unsigned char recrc[4];
67 for (rc=rs=s=0; !rc; s++) switch(s)
68 {
69 case 0:
70 if (is_server)
71 {
72 if (!client[cs_idx].udp_fd) return(-9);
73 if (is_udp)
74 rs=recv_from_udpipe(buf);
75 else
76 rs=recv(client[cs_idx].udp_fd, buf, l, 0);
77 }
78 else
79 {
80 if (!client[cs_idx].udp_fd) return(-9);
81 rs=recv(client[cs_idx].udp_fd, buf, l, 0);
82 }
83 if (rs<24) rc=-1;
84 break;
85 case 1:
86 memcpy(recrc, buf, 4);
87 memmove(buf, buf+4, rs-=4);
88 switch (camd35_auth_client(recrc))
89 {
90 case 0: break; // ok
91 case 1: rc=-2; break; // unknown user
92 default: rc=-9; break; // error's from cs_auth()
93 }
94 break;
95 case 2:
96 aes_decrypt(buf, rs);
97 cs_ddump(buf, rs, "received %d bytes from %s", rs, remote_txt());
98 if (rs!=boundary(4, rs))
99 cs_debug("WARNING: packet size has wrong decryption boundary");
100 //n=(buf[0]==3) ? n=0x34 : 0; this was original, but statement below seems more logical -- dingo35
101 n=(buf[0]==3) ? 0x34 : 0;
102 n=boundary(4, n+20+buf[1]);
103 if (n<rs)
104 cs_debug("ignoring %d bytes of garbage", rs-n);
105 else
106 if (n>rs) rc=-3;
107 break;
108 case 3:
109 if (crc32(0L, buf+20, buf[1])!=b2i(4, buf+4)) rc=-4;
110 if (!rc) rc=n;
111 break;
112 }
113 if ((rs>0) && ((rc==-1)||(rc==-2)))
114 cs_ddump(buf, rs, "received %d bytes from %s (native)", rs, remote_txt);
115 client[cs_idx].last=time((time_t *) 0);
116 switch(rc)
117 {
118 case -1: cs_log("packet to small (%d bytes)", rs);
119 break;
120 case -2: cs_auth_client(0, "unknown user");
121 break;
122 case -3: cs_log("incomplete request !");
123 break;
124 case -4: cs_log("checksum error (wrong password ?)");
125 break;
126 }
127 return(rc);
128}
129
130/*
131 * server functions
132 */
133
134static void camd35_request_emm(ECM_REQUEST *er)
135{
136 int i, au;
137 time_t now;
138 static time_t last=0;
139 static int disable_counter=0;
140 static uchar lastserial[8]={0,0,0,0,0,0,0,0};
141
142 au=client[cs_idx].au;
143 if ((au<0) || (au>CS_MAXREADER)) return; // TODO
144
145 time(&now);
146 if (!memcmp(lastserial, reader[au].hexserial, 8))
147 if (abs(now-last)<180) return;
148 memcpy(lastserial, reader[au].hexserial, 8);
149 last=now;
150
151 if (reader[au].caid[0])
152 {
153 disable_counter=0;
154 log_emm_request(au);
155 }
156 else
157 if (disable_counter>2)
158 return;
159 else
160 disable_counter++;
161
162// if (reader[au].hexserial[3])
163// {
164// if (!reader[au].online)
165// {
166// memset(lastserial, 0, sizeof(lastserial));
167// return;
168// }
169 memset(mbuf, 0, sizeof(mbuf));
170 mbuf[2]=mbuf[3]=0xff; // must not be zero
171 memcpy(mbuf+ 8, i2b(2, er->srvid), 2);
172 memcpy(mbuf+12, i2b(4, er->prid ), 4);
173 memcpy(mbuf+16, i2b(2, er->pid ), 2);
174 mbuf[0]=5;
175 mbuf[1]=111;
176 if (reader[au].caid[0])
177 {
178 mbuf[39]=1; // no. caids
179 mbuf[20]=reader[au].caid[0]>>8; // caid's (max 8)
180 mbuf[21]=reader[au].caid[0]&0xff;
181 memcpy(mbuf+40, reader[au].hexserial, 6); // serial now 6 bytes
182 mbuf[47]=reader[au].nprov;
183 for (i=0; i<reader[au].nprov; i++)
184 {
185 if (((reader[au].caid[0] >= 0x1700) && (reader[au].caid[0] <= 0x1799)) || // Betacrypt
186 ((reader[au].caid[0] >= 0x0600) && (reader[au].caid[0] <= 0x0699))) // Irdeto (don't know if this is correct, cause I don't own a IRDETO-Card)
187 {
188 mbuf[48+(i*5)]=reader[au].prid[i][0];
189 memcpy(&mbuf[50+(i*5)], &reader[au].prid[i][1], 3);
190 }
191 else
192 {
193 mbuf[48+(i*5)]=reader[au].prid[i][2];
194 mbuf[49+(i*5)]=reader[au].prid[i][3];
195 memcpy(&mbuf[50+(i*5)], &reader[au].sa[i][0],3);
196 }
197 }/* b_nano old implementation was not working according to documentation, so we changed it
198 mbuf[128]=(reader[au].b_nano[0xd0])?0:1;
199 mbuf[129]=(reader[au].b_nano[0xd2])?0:1;
200 mbuf[130]=(reader[au].b_nano[0xd3])?0:1;*/
201 //we think client/server protocols should deliver all information, and only readers should discard EMM
202 mbuf[128]=1; //if 0, GA EMM is blocked
203 mbuf[129]=1; //if 0, SA EMM is blocked
204 mbuf[130]=1; //if 0, UA EMM is blocked
205 }
206 else // disable emm
207 mbuf[20]=mbuf[39]=mbuf[40]=mbuf[47]=mbuf[49]=1;
208 memcpy(mbuf+10, mbuf+20, 2);
209 camd35_send(mbuf); // send with data-len 111 for camd3 > 3.890
210 mbuf[1]++;
211 camd35_send(mbuf); // send with data-len 112 for camd3 < 3.890
212// }
213}
214
215static void camd35_send_dcw(ECM_REQUEST *er)
216{
217 uchar *buf;
218 buf=req+(er->cpti*REQ_SIZE); // get orig request
219
220 if (((er->rcEx > 0) || (er->rc == 8)) && !client[cs_idx].c35_suppresscmd08)
221 {
222 buf[0]=0x08;
223 buf[1]=2;
224 memset(buf+20, 0, buf[1]);
225 }
226 else
227 {
228 // Send CW
229 if ((er->rc < 4) || (er->rc == 7))
230 {
231 if (buf[0]==3)
232 memmove(buf+20+16, buf+20+buf[1], 0x34);
233 buf[0]++;
234 buf[1]=16;
235 memcpy(buf+20, er->cw, buf[1]);
236 }
237 else
238 {
239 // Send old CMD44 to prevent cascading problems with older mpcs/oscam versions
240 buf[0]=0x44;
241 buf[1]=0;
242 }
243 }
244 camd35_send(buf);
245 camd35_request_emm(er);
246}
247
248static void camd35_process_ecm(uchar *buf)
249{
250 ECM_REQUEST *er;
251 if (!(er=get_ecmtask()))
252 return;
253 er->l=buf[1];
254 memcpy(req+(er->cpti*REQ_SIZE), buf, 0x34+20+er->l); // save request
255 er->srvid=b2i(2, buf+ 8);
256 er->caid =b2i(2, buf+10);
257 er->prid =b2i(4, buf+12);
258 er->pid =b2i(2, buf+16);
259 memcpy(er->ecm, buf+20, er->l);
260 get_cw(er);
261}
262
263static void camd35_process_emm(uchar *buf)
264{
265 int au;
266 memset(&epg, 0, sizeof(epg));
267 au=client[cs_idx].au;
268 if ((au<0) || (au>CS_MAXREADER)) return; // TODO
269 epg.l=buf[1];
270 memcpy(epg.caid , buf+10 , 2);
271 memcpy(epg.provid , buf+12 , 4);
272 memcpy(epg.emm , buf+20 , epg.l);
273 do_emm(&epg);
274}
275
276static void camd35_server()
277{
278 int n;
279
280 req=(uchar *)malloc(CS_MAXPENDING*REQ_SIZE);
281 if (!req)
282 {
283 cs_log("Cannot allocate memory (errno=%d)", errno);
284 cs_exit(1);
285 }
286 memset(req, 0, CS_MAXPENDING*REQ_SIZE);
287
288 is_udp = (ph[client[cs_idx].ctyp].type == MOD_CONN_UDP);
289
290 while ((n=process_input(mbuf, sizeof(mbuf), cfg->cmaxidle))>0)
291 {
292 switch(mbuf[0])
293 {
294 case 0: // ECM
295 case 3: // ECM (cascading)
296 camd35_process_ecm(mbuf);
297 break;
298 case 6: // EMM
299 case 19: // EMM
300 camd35_process_emm(mbuf);
301 break;
302 default:
303 cs_log("unknown camd35 command! (%d)", mbuf[0]);
304 }
305 }
306
307 if(req) { free(req); req=0;}
308
309 cs_disconnect_client();
310}
311
312/*
313 * client functions
314 */
315
316static void casc_set_account()
317{
318 strcpy((char *)upwd, reader[ridx].r_pwd);
319 memcpy(client[cs_idx].ucrc, i2b(4, crc32(0L, MD5((unsigned char *)reader[ridx].r_usr, strlen(reader[ridx].r_usr), NULL), 16)), 4);
320 aes_set_key((char *)MD5(upwd, strlen((char *)upwd), NULL));
321 client[cs_idx].crypted=1;
322}
323
324int camd35_client_init()
325{
326 static struct sockaddr_in loc_sa;
327 struct protoent *ptrp;
328 int p_proto;//, sock_type;
329 char ptxt[16];
330
331 pfd=0;
332 if (reader[ridx].r_port<=0)
333 {
334 cs_log("invalid port %d for server %s", reader[ridx].r_port, reader[ridx].device);
335 return(1);
336 }
337 is_udp=(reader[ridx].typ==R_CAMD35);
338 if( (ptrp=getprotobyname(is_udp ? "udp" : "tcp")) )
339 p_proto=ptrp->p_proto;
340 else
341 p_proto=(is_udp) ? 17 : 6; // use defaults on error
342
343 client[cs_idx].ip=0;
344 memset((char *)&loc_sa,0,sizeof(loc_sa));
345 loc_sa.sin_family = AF_INET;
346#ifdef LALL
347 if (cfg->serverip[0])
348 loc_sa.sin_addr.s_addr = inet_addr(cfg->serverip);
349 else
350#endif
351 loc_sa.sin_addr.s_addr = INADDR_ANY;
352 loc_sa.sin_port = htons(reader[ridx].l_port);
353
354 if ((client[cs_idx].udp_fd=socket(PF_INET, is_udp ? SOCK_DGRAM : SOCK_STREAM, p_proto))<0)
355 {
356 cs_log("Socket creation failed (errno=%d)", errno);
357 cs_exit(1);
358 }
359
360#ifdef SO_PRIORITY
361 if (cfg->netprio)
362 setsockopt(client[cs_idx].udp_fd, SOL_SOCKET, SO_PRIORITY, (void *)&cfg->netprio, sizeof(ulong));
363#endif
364
365 if (reader[ridx].l_port>0)
366 {
367 if (bind(client[cs_idx].udp_fd, (struct sockaddr *)&loc_sa, sizeof (loc_sa))<0)
368 {
369 cs_log("bind failed (errno=%d)", errno);
370 close(client[cs_idx].udp_fd);
371 return(1);
372 }
373 sprintf(ptxt, ", port=%d", reader[ridx].l_port);
374 }
375 else
376 ptxt[0]='\0';
377
378 casc_set_account();
379 memset((char *)&client[cs_idx].udp_sa, 0, sizeof(client[cs_idx].udp_sa));
380 client[cs_idx].udp_sa.sin_family=AF_INET;
381 client[cs_idx].udp_sa.sin_port=htons((u_short)reader[ridx].r_port);
382
383 cs_log("proxy %s:%d (fd=%d%s)",
384 reader[ridx].device, reader[ridx].r_port,
385 client[cs_idx].udp_fd, ptxt);
386
387 if (is_udp) pfd=client[cs_idx].udp_fd;
388
389 return(0);
390}
391
392int camd35_client_init_log()
393{
394 static struct sockaddr_in loc_sa;
395 struct protoent *ptrp;
396 int p_proto;
397
398 if (reader[ridx].log_port<=0)
399 {
400 cs_log("invalid port %d for camd3-loghost", reader[ridx].log_port);
401 return(1);
402 }
403
404 ptrp=getprotobyname("udp");
405 if (ptrp)
406 p_proto=ptrp->p_proto;
407 else
408 p_proto=17; // use defaults on error
409
410 memset((char *)&loc_sa,0,sizeof(loc_sa));
411 loc_sa.sin_family = AF_INET;
412 loc_sa.sin_addr.s_addr = INADDR_ANY;
413 loc_sa.sin_port = htons(reader[ridx].log_port);
414
415 if ((logfd=socket(PF_INET, SOCK_DGRAM, p_proto))<0)
416 {
417 cs_log("Socket creation failed (errno=%d)", errno);
418 return(1);
419 }
420
421 if (bind(logfd, (struct sockaddr *)&loc_sa, sizeof(loc_sa))<0)
422 {
423 cs_log("bind failed (errno=%d)", errno);
424 close(logfd);
425 return(1);
426 }
427
428 cs_log("camd3 loghost initialized (fd=%d, port=%d)",
429 logfd, reader[ridx].log_port);
430
431 return(0);
432}
433
434static int tcp_connect()
435{
436 if (!reader[ridx].tcp_connected)
437 {
438 int handle=0;
439 handle = network_tcp_connection_open();
440 if (handle<0) return(0);
441
442 reader[ridx].tcp_connected = 1;
443 reader[ridx].last_s = reader[ridx].last_g = time((time_t *)0);
444 pfd = client[cs_idx].udp_fd = handle;
445 }
446 if (!client[cs_idx].udp_fd) return(0);
447 return(1);
448}
449
450static int camd35_send_ecm(ECM_REQUEST *er, uchar *buf)
451{
452 if (!client[cs_idx].udp_sa.sin_addr.s_addr) // once resolved at least
453 return(-1);
454
455 if (!is_udp && !tcp_connect()) return(-1);
456
457 memset(buf, 0, 20);
458 memset(buf+20, 0xff, er->l+15);
459 buf[1]=er->l;
460 memcpy(buf+ 8, i2b(2, er->srvid), 2);
461 memcpy(buf+10, i2b(2, er->caid ), 2);
462 memcpy(buf+12, i2b(4, er->prid ), 4);
463// memcpy(buf+16, i2b(2, er->pid ), 2);
464// memcpy(buf+16, &er->idx , 2);
465 memcpy(buf+16, i2b(2, er->idx ), 2);
466 buf[18]=0xff;
467 buf[19]=0xff;
468 memcpy(buf+20, er->ecm , er->l);
469 return((camd35_send(buf)<1) ? (-1) : 0);
470}
471
472static int camd35_recv_chk(uchar *dcw, int *rc, uchar *buf)
473{
474 ushort idx;
475
476 // CMD44: old reject command introduced in mpcs
477 // keeping this for backward compatibility
478 if ((buf[0] != 1) && (buf[0] != 0x44) && (buf[0] != 0x08))
479 return(-1);
480
481 idx=b2i(2, buf+16);
482
483 *rc=((buf[0] != 0x44) && (buf[0] != 0x08));
484
485 memcpy(dcw, buf+20, 16);
486 return(idx);
487}
488
489static int camd35_recv_log(ushort *caid, ulong *provid, ushort *srvid)
490{
491 int i;
492 uchar buf[512], *ptr, *ptr2;
493 ushort idx=0;
494 if (!logfd) return(-1);
495 if ((i=recv(logfd, buf, sizeof(buf), 0))<=0) return(-1);
496 buf[i]=0;
497
498 if (!(ptr=(uchar *)strstr((char *)buf, " -> "))) return(-1);
499 ptr+=4;
500 if (strstr((char *)ptr, " decoded ")) return(-1); // skip "found"s
501 if (!(ptr2=(uchar *)strchr((char *)ptr, ' '))) return(-1); // corrupt
502 *ptr2=0;
503
504 for (i=0, ptr2=(uchar *)strtok((char *)ptr, ":"); ptr2; i++, ptr2=(uchar *)strtok(NULL, ":"))
505 {
506 trim((char *)ptr2);
507 switch(i)
508 {
509 case 0: *caid =cs_atoi((char *)ptr2, strlen((char *)ptr2)>>1, 0); break;
510 case 1: *provid=cs_atoi((char *)ptr2, strlen((char *)ptr2)>>1, 0); break;
511 case 2: *srvid =cs_atoi((char *)ptr2, strlen((char *)ptr2)>>1, 0); break;
512 case 3: idx =cs_atoi((char *)ptr2, strlen((char *)ptr2)>>1, 0); break;
513 }
514 if (errno) return(-1);
515 }
516 return(idx&0x1FFF);
517}
518
519/*
520 * module definitions
521 */
522
523void module_camd35(struct s_module *ph)
524{
525 static PTAB ptab;
526 ptab.ports[0].s_port = cfg->c35_port;
527 ph->ptab = &ptab;
528 ph->ptab->nports = 1;
529
530 strcpy(ph->desc, "camd 3.5x");
531 ph->type=MOD_CONN_UDP;
532 ph->multi=1;
533 ph->watchdog=1;
534 ph->s_ip=cfg->c35_srvip;
535 ph->s_handler=camd35_server;
536 ph->recv=camd35_recv;
537 ph->send_dcw=camd35_send_dcw;
538 ph->c_multi=1;
539 ph->c_init=camd35_client_init;
540 ph->c_recv_chk=camd35_recv_chk;
541 ph->c_send_ecm=camd35_send_ecm;
542 ph->c_init_log=camd35_client_init_log;
543 ph->c_recv_log=camd35_recv_log;
544}
545
546void module_camd35_tcp(struct s_module *ph)
547{
548 strcpy(ph->desc, "cs378x");
549 ph->type=MOD_CONN_TCP;
550 ph->multi=1;
551 ph->watchdog=1;
552 ph->ptab=&cfg->c35_tcp_ptab;
553 if (ph->ptab->nports==0)
554 ph->ptab->nports=1; // show disabled in log
555 ph->s_ip=cfg->c35_tcp_srvip;
556 ph->s_handler=camd35_server;
557 ph->recv=camd35_recv;
558 ph->send_dcw=camd35_send_dcw;
559 ph->c_multi=1;
560 ph->c_init=camd35_client_init;
561 ph->c_recv_chk=camd35_recv_chk;
562 ph->c_send_ecm=camd35_send_ecm;
563 ph->c_init_log=camd35_client_init_log;
564 ph->c_recv_log=camd35_recv_log;
565}
Note: See TracBrowser for help on using the repository browser.