source: trunk/module-camd35.c@ 8

Last change on this file since 8 was 8, checked in by smurzch2, 12 years ago

Start repository for OSCam (Open Source Cam)

The start is from the MpCS source code. Thanks a lot to the authors for this
great sources.

File size: 13.3 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(account->usr, strlen(account->usr), NULL), 16))
43 {
44 memcpy(client[cs_idx].ucrc, ucrc, 4);
45 strcpy(upwd, account->pwd);
46 aes_set_key(MD5(upwd, strlen(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 free(req);
279 cs_disconnect_client();
280}
281
282/*
283 * client functions
284 */
285
286static void casc_set_account()
287{
288 strcpy(upwd, reader[ridx].r_pwd);
289 memcpy(client[cs_idx].ucrc, i2b(4, crc32(0L, MD5(reader[ridx].r_usr, strlen(reader[ridx].r_usr), NULL), 16)), 4);
290 aes_set_key(MD5(upwd, strlen(upwd), NULL));
291 client[cs_idx].crypted=1;
292}
293
294int camd35_client_init()
295{
296 static struct sockaddr_in loc_sa;
297 struct protoent *ptrp;
298 int p_proto;//, sock_type;
299 char ptxt[16];
300
301 pfd=0;
302 if (reader[ridx].r_port<=0)
303 {
304 cs_log("invalid port %d for server %s", reader[ridx].r_port, reader[ridx].device);
305 return(1);
306 }
307 is_udp=(reader[ridx].typ==R_CAMD35);
308 if( (ptrp=getprotobyname(is_udp ? "udp" : "tcp")) )
309 p_proto=ptrp->p_proto;
310 else
311 p_proto=(is_udp) ? 17 : 6; // use defaults on error
312
313 client[cs_idx].ip=0;
314 memset((char *)&loc_sa,0,sizeof(loc_sa));
315 loc_sa.sin_family = AF_INET;
316#ifdef LALL
317 if (cfg->serverip[0])
318 loc_sa.sin_addr.s_addr = inet_addr(cfg->serverip);
319 else
320#endif
321 loc_sa.sin_addr.s_addr = INADDR_ANY;
322 loc_sa.sin_port = htons(reader[ridx].l_port);
323
324 if ((client[cs_idx].udp_fd=socket(PF_INET, is_udp ? SOCK_DGRAM : SOCK_STREAM, p_proto))<0)
325 {
326 cs_log("Socket creation failed (errno=%d)", errno);
327 cs_exit(1);
328 }
329
330#ifdef SO_PRIORITY
331 if (cfg->netprio)
332 setsockopt(client[cs_idx].udp_fd, SOL_SOCKET, SO_PRIORITY, (void *)&cfg->netprio, sizeof(ulong));
333#endif
334
335 if (reader[ridx].l_port>0)
336 {
337 if (bind(client[cs_idx].udp_fd, (struct sockaddr *)&loc_sa, sizeof (loc_sa))<0)
338 {
339 cs_log("bind failed (errno=%d)", errno);
340 close(client[cs_idx].udp_fd);
341 return(1);
342 }
343 sprintf(ptxt, ", port=%d", reader[ridx].l_port);
344 }
345 else
346 ptxt[0]='\0';
347
348 casc_set_account();
349 memset((char *)&client[cs_idx].udp_sa, 0, sizeof(client[cs_idx].udp_sa));
350 client[cs_idx].udp_sa.sin_family=AF_INET;
351 client[cs_idx].udp_sa.sin_port=htons((u_short)reader[ridx].r_port);
352
353 cs_log("proxy %s:%d (fd=%d%s)",
354 reader[ridx].device, reader[ridx].r_port,
355 client[cs_idx].udp_fd, ptxt);
356
357 if (is_udp) pfd=client[cs_idx].udp_fd;
358
359 return(0);
360}
361
362int camd35_client_init_log()
363{
364 static struct sockaddr_in loc_sa;
365 struct protoent *ptrp;
366 int p_proto;
367
368 if (reader[ridx].log_port<=0)
369 {
370 cs_log("invalid port %d for camd3-loghost", reader[ridx].log_port);
371 return(1);
372 }
373
374 if (ptrp=getprotobyname("udp"))
375 p_proto=ptrp->p_proto;
376 else
377 p_proto=17; // use defaults on error
378
379 memset((char *)&loc_sa,0,sizeof(loc_sa));
380 loc_sa.sin_family = AF_INET;
381 loc_sa.sin_addr.s_addr = INADDR_ANY;
382 loc_sa.sin_port = htons(reader[ridx].log_port);
383
384 if ((logfd=socket(PF_INET, SOCK_DGRAM, p_proto))<0)
385 {
386 cs_log("Socket creation failed (errno=%d)", errno);
387 return(1);
388 }
389
390 if (bind(logfd, (struct sockaddr *)&loc_sa, sizeof(loc_sa))<0)
391 {
392 cs_log("bind failed (errno=%d)", errno);
393 close(logfd);
394 return(1);
395 }
396
397 cs_log("camd3 loghost initialized (fd=%d, port=%d)",
398 logfd, reader[ridx].log_port);
399
400 return(0);
401}
402
403static int tcp_connect()
404{
405 if (!reader[ridx].tcp_connected)
406 {
407 int handle=0;
408 handle = network_tcp_connection_open(reader[ridx].device, reader[ridx].r_port);
409 if (handle<0) return(0);
410
411 reader[ridx].tcp_connected = 1;
412 reader[ridx].last_s = reader[ridx].last_g = time((time_t *)0);
413 pfd = client[cs_idx].udp_fd = handle;
414 }
415 if (!client[cs_idx].udp_fd) return(0);
416 return(1);
417}
418
419static int camd35_send_ecm(ECM_REQUEST *er, uchar *buf)
420{
421 if (!client[cs_idx].udp_sa.sin_addr.s_addr) // once resolved at least
422 return(-1);
423
424 if (!is_udp && !tcp_connect()) return(-1);
425
426 memset(buf, 0, 20);
427 memset(buf+20, 0xff, er->l+15);
428 buf[1]=er->l;
429 memcpy(buf+ 8, i2b(2, er->srvid), 2);
430 memcpy(buf+10, i2b(2, er->caid ), 2);
431 memcpy(buf+12, i2b(4, er->prid ), 4);
432// memcpy(buf+16, i2b(2, er->pid ), 2);
433// memcpy(buf+16, &er->idx , 2);
434 memcpy(buf+16, i2b(2, er->idx ), 2);
435 buf[18]=0xff;
436 buf[19]=0xff;
437 memcpy(buf+20, er->ecm , er->l);
438 return((camd35_send(buf)<1) ? (-1) : 0);
439}
440
441static int camd35_recv_chk(uchar *dcw, int *rc, uchar *buf, int n)
442{
443 //int i;
444 ushort idx;
445
446 if ((buf[0]!=1) && (buf[0]!=0x44)) // no cw, ignore others
447 return(-1);
448// memcpy(&idx, buf+16, 2);
449 idx=b2i(2, buf+16);
450 *rc=(buf[0]!=0x44);
451 memcpy(dcw, buf+20, 16);
452 return(idx);
453}
454
455static int camd35_recv_log(ushort *caid, ulong *provid, ushort *srvid)
456{
457 int i;
458 uchar buf[512], *ptr, *ptr2;
459 ushort idx;
460 if (!logfd) return(-1);
461 if ((i=recv(logfd, buf, sizeof(buf), 0))<=0) return(-1);
462 buf[i]=0;
463
464 if (!(ptr=strstr(buf, " -> "))) return(-1);
465 ptr+=4;
466 if (strstr(ptr, " decoded ")) return(-1); // skip "found"s
467 if (!(ptr2=strchr(ptr, ' '))) return(-1); // corrupt
468 *ptr2=0;
469
470 for (i=0, ptr2=strtok(ptr, ":"); ptr2; i++, ptr2=strtok(NULL, ":"))
471 {
472 trim(ptr2);
473 switch(i)
474 {
475 case 0: *caid =cs_atoi(ptr2, strlen(ptr2)>>1, 0); break;
476 case 1: *provid=cs_atoi(ptr2, strlen(ptr2)>>1, 0); break;
477 case 2: *srvid =cs_atoi(ptr2, strlen(ptr2)>>1, 0); break;
478 case 3: idx =cs_atoi(ptr2, strlen(ptr2)>>1, 0); break;
479 }
480 if (errno) return(-1);
481 }
482 return(idx&0x1FFF);
483}
484
485/*
486 * module definitions
487 */
488
489void module_camd35(struct s_module *ph)
490{
491 static PTAB ptab;
492 ptab.ports[0].s_port = cfg->c35_port;
493 ph->ptab = &ptab;
494 ph->ptab->nports = 1;
495
496 strcpy(ph->desc, "camd 3.5x");
497 ph->type=MOD_CONN_UDP;
498 ph->multi=1;
499 ph->watchdog=1;
500 ph->s_ip=cfg->c35_srvip;
501 ph->s_handler=camd35_server;
502 ph->recv=camd35_recv;
503 ph->send_dcw=camd35_send_dcw;
504 ph->c_multi=1;
505 ph->c_init=camd35_client_init;
506 ph->c_recv_chk=camd35_recv_chk;
507 ph->c_send_ecm=camd35_send_ecm;
508 ph->c_init_log=camd35_client_init_log;
509 ph->c_recv_log=camd35_recv_log;
510}
511
512void module_camd35_tcp(struct s_module *ph)
513{
514 strcpy(ph->desc, "cs378x");
515 ph->type=MOD_CONN_TCP;
516 ph->multi=1;
517 ph->watchdog=1;
518 ph->ptab=&cfg->c35_tcp_ptab;
519 if (ph->ptab->nports==0)
520 ph->ptab->nports=1; // show disabled in log
521 ph->s_ip=cfg->c35_tcp_srvip;
522 ph->s_handler=camd35_server;
523 ph->recv=camd35_recv;
524 ph->send_dcw=camd35_send_dcw;
525 ph->c_multi=1;
526 ph->c_init=camd35_client_init;
527 ph->c_recv_chk=camd35_recv_chk;
528 ph->c_send_ecm=camd35_send_ecm;
529 ph->c_init_log=camd35_client_init_log;
530 ph->c_recv_log=camd35_recv_log;
531}
Note: See TracBrowser for help on using the repository browser.