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.