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.