source: trunk/module-camd35.c @ 431

Last change on this file since 431 was 70, checked in by rorothetroll, 11 years ago

csctapi/io_serial.c : fix the serial port read/write wait routine to use select instead of poll

This make them compatible with Mac OS X and now oscamd works on OS X. The same code off course
still works on linux and other unix platforms. I let that code ran for 24h before commiting this code.
If you have any issue let me know and I'llr evert to poll for non compatible machines.

all the others : fix all the warning due to sign difference (mostly uchar versus char). This make the code compile

with -Werror on the more strict version of gcc (which is the case on OS X). I also noticed that in a lot of places
the code use a buffer defined as an uchar * ... and use strings functions (strnXXXX) where some memcpy/memcmp .. function
would have been preferable as we're suposedly manipulation a binary buffer. Anyway I fixed all of them and it now compile
without any warning or error on linux and OS X (and also probably on all the other unices but we will have to try before
adding -Werror on the other platform).

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