source: trunk/module-radegast.c @ 5375

Last change on this file since 5375 was 5299, checked in by Admin, 8 years ago

Replace all malloc/calloc calls (in main OSCam directory) with cs_malloc and add handling for memory allocation failures.

File size: 7.7 KB
Line 
1#include "globals.h"
2
3static int32_t radegast_send(struct s_client * client, uchar *buf)
4{
5  int32_t l=buf[1]+2;
6  return(send(client->pfd, buf, l, 0));
7}
8
9static int32_t radegast_recv(struct s_client *client, uchar *buf, int32_t l)
10{
11  int32_t n;
12  if (!client->pfd) return(-1);
13  if (client->typ == 'c') {  // server code
14    if ((n=recv(client->pfd, buf, l, 0))>0)
15      client->last=time((time_t *) 0);
16  } else {  // client code
17    if ((n=recv(client->pfd, buf, l, 0))>0) {
18      cs_ddump_mask(D_CLIENT, buf, n, "radegast: received %d bytes from %s", n, remote_txt());
19      client->last = time((time_t *) 0);
20
21      if (buf[0] == 2) {  // dcw received
22        if (buf[3] != 0x10) {  // dcw ok
23          cs_log("radegast: no dcw");
24          n = -1;
25        }
26      }
27    }
28  }
29  return(n);
30}
31
32static int32_t radegast_recv_chk(struct s_client *client, uchar *dcw, int32_t *rc, uchar *buf, int32_t UNUSED(n))
33{
34  if ((buf[0] == 2) && (buf[1] == 0x12)) {
35    memcpy(dcw, buf+4, 16);
36    cs_debug_mask(D_CLIENT, "radegast: recv chk - %s", cs_hexdump(0, dcw, 16));
37    *rc = 1;
38    return(client->reader->msg_idx);
39  }
40
41  return (-1);
42}
43
44static void radegast_auth_client(in_addr_t ip)
45{
46  int32_t ok;
47  struct s_auth *account;
48
49  ok = check_ip(cfg.rad_allowed, ip);
50
51  if (!ok)
52  {
53    cs_auth_client(cur_client(), (struct s_auth *)0, NULL);
54    cs_exit(0);
55  }
56
57  for (ok=0, account=cfg.account; (cfg.rad_usr[0]) && (account) && (!ok); account=account->next)
58  {
59    ok=(!strcmp(cfg.rad_usr, account->usr));
60    if (ok && cs_auth_client(cur_client(), account, NULL))
61      cs_exit(0);
62  }
63
64  if (!ok)
65    cs_auth_client(cur_client(), (struct s_auth *)(-1), NULL);
66}
67
68static int32_t get_request(uchar *buf)
69{
70  int32_t n, rc=0;
71  if ((n=process_input(buf, 2, cfg.cmaxidle))==2)
72  {
73    if ((n=process_input(buf+2, buf[1], 0))>=0)
74      n+=2;
75    if (n-2==buf[1])
76      rc=n;
77    else
78      cs_log("WARNING: protocol error (garbage)");
79  }
80  if (n>0)
81  {
82    cs_ddump_mask(D_CLIENT, buf, n, "received %d bytes from client", n);
83  }
84  return(rc);
85}
86
87static void radegast_send_dcw(struct s_client *client, ECM_REQUEST *er)
88{
89  uchar mbuf[1024];
90  mbuf[0]=0x02;     // DCW
91  if (er->rc < E_NOTFOUND)
92  {
93    mbuf[1]=0x12;   // len (overall)
94    mbuf[2]=0x05;   // ACCESS
95    mbuf[3]=0x10;   // len
96    memcpy(mbuf+4, er->cw, 16);
97  }
98  else
99  {
100    mbuf[1]=0x02;   // len (overall)
101    mbuf[2]=0x04;   // NO ACCESS
102    mbuf[3]=0x00;   // len
103  }
104  radegast_send(client, mbuf);
105}
106
107static void radegast_process_ecm(uchar *buf, int32_t l)
108{
109  int32_t i, n, sl;
110  ECM_REQUEST *er;
111
112  if (!(er=get_ecmtask()))
113    return;
114  for (i=0; i<l; i+=(sl+2))
115  {
116    sl=buf[i+1];
117    switch(buf[i])
118    {
119      case  2:      // CAID (upper byte only, oldstyle)
120        er->caid=buf[i+2]<<8;
121        break;
122      case 10:      // CAID
123        er->caid=b2i(2, buf+i+2);
124        break;
125      case  3:      // ECM DATA
126        er->l=sl;
127        memcpy(er->ecm, buf+i+2, er->l);
128        break;
129      case  6:      // PROVID (ASCII)
130        n=(sl>6) ? 3 : (sl>>1);
131        er->prid=cs_atoi((char *) buf+i+2+sl-(n<<1), n, 0);
132        break;
133      case  7:      // KEYNR (ASCII), not needed
134        break;
135      case  8:      // ECM PROCESS PID ?? don't know, not needed
136        break;
137    }
138  }
139  if (l!=i)
140    cs_log("WARNING: ECM-request corrupt");
141  else
142    get_cw(cur_client(), er);
143}
144
145static void radegast_process_unknown(uchar *buf)
146{
147  uchar answer[2]={0x81, 0x00};
148  radegast_send(cur_client(), answer);
149  cs_log("unknown request %02X, len=%d", buf[0], buf[1]);
150}
151
152static void * radegast_server(void *cli)
153{
154  int32_t n;
155  uchar mbuf[1024];
156
157    struct s_client * client = (struct s_client *) cli;
158  client->thread=pthread_self();
159  pthread_setspecific(getclient, cli);
160
161  radegast_auth_client(cur_client()->ip);
162  while ((n=get_request(mbuf))>0)
163  {
164    switch(mbuf[0])
165    {
166      case 1:
167        radegast_process_ecm(mbuf+2, mbuf[1]);
168        break;
169      default:
170        radegast_process_unknown(mbuf);
171    }
172  }
173  cs_disconnect_client(client);
174  return NULL;
175}
176
177static int32_t radegast_send_ecm(struct s_client *client, ECM_REQUEST *er, uchar *UNUSED(buf))
178{
179  int32_t n;
180  uchar provid_buf[8];
181  uchar header[22] = "\x02\x01\x00\x06\x08\x30\x30\x30\x30\x30\x30\x30\x30\x07\x04\x30\x30\x30\x38\x08\x01\x02"; 
182  uchar *ecmbuf;
183  if(!cs_malloc(&ecmbuf,er->l + 30, -1)) return -1;
184
185  ecmbuf[0] = 1;
186  ecmbuf[1] = er->l + 30 - 2;
187  memcpy(ecmbuf + 2, header, sizeof(header));
188  for(n = 0; n < 4; n++) {
189    snprintf((char*)provid_buf+(n*2), sizeof(provid_buf)-(n*2), "%02X", ((uchar *)(&er->prid))[4 - 1 - n]);
190  }
191  ecmbuf[7] = provid_buf[0];
192  ecmbuf[8] = provid_buf[1];
193  ecmbuf[9] = provid_buf[2];
194  ecmbuf[10] = provid_buf[3];
195  ecmbuf[11] = provid_buf[4];
196  ecmbuf[12] = provid_buf[5];
197  ecmbuf[13] = provid_buf[6];
198  ecmbuf[14] = provid_buf[7];
199  ecmbuf[2 + sizeof(header)] = 0xa;
200  ecmbuf[3 + sizeof(header)] = 2;
201  ecmbuf[4 + sizeof(header)] = er->caid >> 8;
202  ecmbuf[5 + sizeof(header)] = er->caid & 0xff;
203  ecmbuf[6 + sizeof(header)] = 3;
204  ecmbuf[7 + sizeof(header)] = er->l;
205  memcpy(ecmbuf + 8 + sizeof(header), er->ecm, er->l);
206  ecmbuf[4] = er->caid >> 8;
207
208  client->reader->msg_idx = er->idx;
209  n = send(client->pfd, ecmbuf, er->l + 30, 0);
210
211  cs_log("radegast: sending ecm");
212  cs_ddump_mask(D_CLIENT, ecmbuf, er->l + 30, "ecm:");
213
214  free(ecmbuf);
215
216  return 0;
217}
218
219int32_t radegast_cli_init(struct s_client *cl)
220{
221  *cl = *cl; //prevent compiler warning
222  struct sockaddr_in loc_sa;
223  int32_t handle;
224
225  cur_client()->pfd=0;
226  if (cur_client()->reader->r_port<=0)
227  {
228    cs_log("radegast: invalid port %d for server %s", cur_client()->reader->r_port, cur_client()->reader->device);
229    return(1);
230  }
231
232  cur_client()->ip=0;
233  memset((char *)&loc_sa,0,sizeof(loc_sa));
234  loc_sa.sin_family = AF_INET;
235#ifdef LALL
236  if (cfg.serverip[0])
237    loc_sa.sin_addr.s_addr = inet_addr(cfg.serverip);
238  else
239#endif
240    loc_sa.sin_addr.s_addr = INADDR_ANY;
241  loc_sa.sin_port = htons(cur_client()->reader->l_port);
242
243  if ((cur_client()->udp_fd=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))<0)
244  {
245    cs_log("radegast: Socket creation failed (errno=%d %s)", errno, strerror(errno));
246    cs_exit(1);
247  }
248
249#ifdef SO_PRIORITY
250  if (cfg.netprio)
251    setsockopt(cur_client()->udp_fd, SOL_SOCKET, SO_PRIORITY,
252               (void *)&cfg.netprio, sizeof(uintptr_t));
253#endif
254  if (!cur_client()->reader->tcp_ito) {
255    uint32_t keep_alive = cur_client()->reader->tcp_ito?1:0;
256    setsockopt(cur_client()->udp_fd, SOL_SOCKET, SO_KEEPALIVE,
257    (void *)&keep_alive, sizeof(uintptr_t));
258  }
259
260  memset((char *)&cur_client()->udp_sa,0,sizeof(cur_client()->udp_sa));
261  cur_client()->udp_sa.sin_family = AF_INET;
262  cur_client()->udp_sa.sin_port = htons((uint16_t)cur_client()->reader->r_port);
263
264  cs_log("radegast: proxy %s:%d (fd=%d)",
265  cur_client()->reader->device, cur_client()->reader->r_port, cur_client()->udp_fd);
266
267  handle = network_tcp_connection_open();
268  if(handle < 0) return -1;
269
270  cur_client()->reader->tcp_connected = 2;
271  cur_client()->reader->card_status = CARD_INSERTED;
272  cur_client()->reader->last_g = cur_client()->reader->last_s = time((time_t *)0);
273
274  cs_debug_mask(D_CLIENT, "radegast: last_s=%d, last_g=%d", cur_client()->reader->last_s, cur_client()->reader->last_g);
275
276  cur_client()->pfd=cur_client()->udp_fd;
277
278  return(0);
279}
280
281void module_radegast(struct s_module *ph)
282{
283  static PTAB ptab; //since there is always only 1 radegast server running, this is threadsafe
284  ptab.ports[0].s_port = cfg.rad_port;
285  ph->ptab = &ptab;
286  ph->ptab->nports = 1;
287
288  cs_strncpy(ph->desc, "radegast", sizeof(ph->desc));
289  ph->type=MOD_CONN_TCP;
290  ph->multi=0;
291  ph->watchdog=1;
292  ph->s_ip=cfg.rad_srvip;
293  ph->s_handler=radegast_server;
294  ph->recv=radegast_recv;
295  ph->send_dcw=radegast_send_dcw;
296  ph->c_multi=0;
297  ph->c_init=radegast_cli_init;
298  ph->c_recv_chk=radegast_recv_chk;
299  ph->c_send_ecm=radegast_send_ecm;
300  ph->num=R_RADEGAST;
301}
Note: See TracBrowser for help on using the repository browser.