source: trunk/oscam-simples.c @ 5375

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

Cleanup memory in pipe on client exit. Fix some possible segfault sources. Fix wrong display of au parameter on WebIf status page if config includes an empty au line.

File size: 33.9 KB
Line 
1//FIXME Not checked on threadsafety yet; after checking please remove this line
2#include <sys/time.h>
3#include "globals.h"
4#include "module-cccam.h"
5
6/* Gets the client associated to the calling thread. */
7struct s_client *cur_client(void){
8    return (struct s_client *) pthread_getspecific(getclient);
9}
10
11/* Gets the unique thread number from the client. Used in monitor and newcamd. */
12int32_t get_threadnum(struct s_client *client) {
13    struct s_client *cl;
14    int32_t count=0;
15
16    for (cl=first_client->next; cl ; cl=cl->next) {
17        if (cl->typ==client->typ)
18            count++;
19        if(cl==client)
20            return count;
21    }
22    return 0;
23}
24
25/* Gets the tmp dir */
26char *get_tmp_dir(){
27  if (cs_tmpdir[0])
28    return cs_tmpdir;
29
30#ifdef OS_CYGWIN32
31  char *d = getenv("TMPDIR");
32  if (!d || !d[0])
33    d = getenv("TMP");
34  if (!d || !d[0])
35    d = getenv("TEMP");
36  if (!d || !d[0])
37    getcwd(cs_tmpdir, sizeof(cs_tmpdir)-1);
38
39  cs_strncpy(cs_tmpdir, d, sizeof(cs_tmpdir));
40  char *p = cs_tmpdir;
41  while(*p) p++;
42  p--;
43  if (*p != '/' && *p != '\\')
44    strcat(cs_tmpdir, "/");
45  strcat(cs_tmpdir, "_oscam");
46#else
47  cs_strncpy(cs_tmpdir, "/tmp/.oscam", sizeof(cs_tmpdir));
48#endif
49  mkdir(cs_tmpdir, S_IRWXU);
50  return cs_tmpdir;
51}
52
53void aes_set_key(char *key)
54{
55  AES_set_decrypt_key((const unsigned char *)key, 128, &cur_client()->aeskey_decrypt);
56  AES_set_encrypt_key((const unsigned char *)key, 128, &cur_client()->aeskey);
57}
58
59void aes_decrypt(uchar *buf, int32_t n)
60{
61  int32_t i;
62  for(i=0; i<n; i+=16)
63    AES_decrypt(buf+i, buf+i, &cur_client()->aeskey_decrypt);
64}
65
66void aes_encrypt_idx(struct s_client *cl, uchar *buf, int32_t n)
67{
68  int32_t i;
69  for(i=0; i<n; i+=16)
70    AES_encrypt(buf+i, buf+i, &cl->aeskey);
71}
72
73/* Creates an AES_ENTRY and adds it to the given linked list. */
74void add_aes_entry(AES_ENTRY **list, uint16_t caid, uint32_t ident, int32_t keyid, uchar *aesKey)
75{
76    AES_ENTRY *new_entry, *next,*current;
77
78    // create the AES key entry for the linked list
79    if(!cs_malloc(&new_entry, sizeof(AES_ENTRY), -1)) return;
80
81    memcpy(new_entry->plainkey, aesKey, 16);
82    new_entry->caid=caid;
83    new_entry->ident=ident;
84    new_entry->keyid=keyid;
85    if(memcmp(aesKey,"\xFF\xFF",2)) {
86        AES_set_decrypt_key((const unsigned char *)aesKey, 128, &(new_entry->key));
87        // cs_log("adding key : %s",cs_hexdump(1,aesKey,16));
88    }
89    else {
90        memset(&new_entry->key,0,sizeof(AES_KEY));
91        // cs_log("adding fake key");
92    }
93    new_entry->next=NULL;
94
95    //if list is empty, new_entry is the new head
96    if(!*list) {
97        *list=new_entry;
98        return;
99    }
100
101    //append it to the list
102    current=*list;
103    next=current->next;
104    while(next) {
105        current=next;
106        next=current->next;
107    }
108
109    current->next=new_entry;
110
111}
112
113/* Parses a single AES_KEYS entry and assigns it to the given list.
114   The expected format for value is caid1@ident1:key0,key1 */
115void parse_aes_entry(AES_ENTRY **list, char *label, char *value) {
116    uint16_t caid, dummy;
117    uint32_t ident;
118    int32_t len;
119    char *tmp;
120    int32_t nb_keys,key_id;
121    uchar aes_key[16];
122    char *save=NULL;
123
124    tmp=strtok_r(value,"@",&save);
125    caid=a2i(tmp,2);
126    tmp=strtok_r(NULL,":",&save);
127    ident=a2i(tmp,3);
128   
129    // now we need to split the key and add the entry to the reader.
130    nb_keys=0;
131    key_id=0;
132    while((tmp=strtok_r(NULL,",",&save))) {
133        dummy=0;
134        len=strlen(tmp);
135        if(len!=32) {
136            dummy=a2i(tmp,1);
137            // FF means the card will do the AES decrypt
138            // 00 means we don't have the aes.
139            if((dummy!=0xFF && dummy!=0x00) || len>2) {
140                key_id++;
141                cs_log("AES key length error .. not adding");
142                continue;
143            }
144            if(dummy==0x00) {
145                key_id++;
146                continue;
147            }
148        }
149        nb_keys++;
150        if(dummy)
151            memset(aes_key,0xFF,16);
152        else
153            key_atob_l(tmp,aes_key,32);
154        // now add the key to the reader... TBD
155        add_aes_entry(list,caid,ident,key_id,aes_key);
156        key_id++;
157    }
158   
159    cs_log("%d AES key(s) added on reader %s for %04x:%06x", nb_keys, label, caid, ident);
160}
161
162/* Clears all entries from an AES list*/
163void aes_clear_entries(AES_ENTRY **list){
164    AES_ENTRY *current, *next;
165
166    current=NULL;
167    next=*list;
168    while(next) {
169        current=next;
170        next=current->next;
171        add_garbage(current);
172    }
173    *list=NULL;
174}
175
176/* Parses multiple AES_KEYS entrys in a reader section and assigns them to the reader.
177   The expected format for value is caid1@ident1:key0,key1;caid2@ident2:key0,key1 */
178void parse_aes_keys(struct s_reader *rdr, char *value){
179   char *entry;
180    char *save=NULL;
181    AES_ENTRY *newlist = NULL, *savelist = rdr->aes_list;
182
183    for (entry=strtok_r(value, ";",&save); entry; entry=strtok_r(NULL, ";",&save)) {
184        parse_aes_entry(&newlist, rdr->label, entry);
185    }
186    rdr->aes_list = newlist;
187    aes_clear_entries(&savelist);   
188   
189    /*
190    AES_ENTRY *current;
191    current=rdr->aes_list;
192    while(current) {
193        cs_log("**************************");
194        cs_log("current = %p",current);
195        cs_log("CAID = %04x",current->caid);
196        cs_log("IDENT = %06x",current->ident);
197        cs_log("keyID = %d",current->keyid);
198        cs_log("next = %p",current->next);
199        cs_log("**************************");
200        current=current->next;
201    }
202    */
203}
204
205int32_t aes_decrypt_from_list(AES_ENTRY *list, uint16_t caid, uint32_t provid,int32_t keyid, uchar *buf, int32_t n)
206{
207    AES_ENTRY *current;
208    AES_KEY   dummy;
209    int32_t i;
210    int32_t ok=1;
211    int32_t error=0;
212
213    current=list;
214    while(current) {
215        if(current->caid==caid && current->ident==provid && current->keyid==keyid)
216            break;
217        current=current->next;
218    }
219
220    if(!current) {
221        cs_log("AES Decrypt : key id %d not found for CAID %04X , provider %06x",keyid,caid,provid);
222        return error; // we don't have the key to decode this buffer.
223        }
224    else {
225        // hack for card that do the AES decrypt themsleves
226        memset(&dummy,0,sizeof(AES_KEY));
227        if(!memcmp(&current->key,&dummy,sizeof(AES_KEY))) {
228            return ok;
229        }
230        // decode the key
231        for(i=0; i<n; i+=16)
232            AES_decrypt(buf+i, buf+i, &(current->key));
233    }
234    return ok; // all ok, key decoded.
235}
236
237int32_t aes_present(AES_ENTRY *list, uint16_t caid, uint32_t provid,int32_t keyid)
238{
239    AES_ENTRY *current;
240    int32_t ok=1;
241    int32_t error=0;
242
243    current=list;
244    while(current) {
245        if(current->caid==caid && current->ident==provid && current->keyid==keyid)
246            break;
247        current=current->next;
248    }
249
250    if(!current) {
251        cs_log("AES Decrypt : key id %d not found for CAID %04X , provider %06x",keyid,caid,provid);
252        return error; // we don't have the key to decode this buffer.
253        }
254   
255    return ok;
256}
257
258char *remote_txt(void)
259{
260  if (cur_client()->typ == 'c')
261    return("client");
262  else
263    return("remote server");
264}
265
266char *trim(txt)
267char *txt;
268{
269  register int32_t l;
270  register char *p1, *p2;
271
272  if (*txt==' ')
273  {
274    for (p1=p2=txt;
275        (*p1==' ') || (*p1=='\t') || (*p1=='\n') || (*p1=='\r');
276         p1++);
277    while (*p1)
278      *p2++=*p1++;
279    *p2='\0';
280  }
281  if ((l=strlen(txt))>0)
282    for (p1=txt+l-1;
283        (*p1==' ') || (*p1=='\t') || (*p1=='\n') || (*p1=='\r');
284         *p1--='\0');
285
286  return(txt);
287}
288
289
290
291int32_t gethexval(char c)
292{
293  if ((c>='0') && (c<='9')) return(c-'0');
294  if ((c>='A') && (c<='F')) return(c-'A'+10);
295  if ((c>='a') && (c<='f')) return(c-'a'+10);
296  return(-1);
297}
298
299int32_t comp_timeb(struct timeb *tpa, struct timeb *tpb)
300{
301  if (tpa->time>tpb->time) return(1);
302  if (tpa->time<tpb->time) return(-1);
303  if (tpa->millitm>tpb->millitm) return(1);
304  if (tpa->millitm<tpb->millitm) return(-1);
305  return(0);
306}
307
308int32_t cs_atob(uchar *buf, char *asc, int32_t n)
309{
310  int32_t i, rc;
311  for (i=0; i<n; i++)
312  {
313    if ((rc=(gethexval(asc[i<<1])<<4)|gethexval(asc[(i<<1)+1]))&0x100)
314      return(-1);
315    buf[i]=rc;
316  }
317  return(n);
318}
319
320uint32_t cs_atoi(char *asc, int32_t l, int32_t val_on_err)
321{
322  int32_t i, n=0;
323  uint32_t rc=0;
324  for (i=((l-1)<<1), errno=0; (i>=0) && (n<4); i-=2)
325  {
326    int32_t b;
327    b=(gethexval(asc[i])<<4) | gethexval(asc[i+1]);
328    if (b<0)
329    {
330      errno=EINVAL;
331      rc=(val_on_err) ? 0xFFFFFFFF : 0;
332      break;
333    }
334    rc|=b<<(n<<3);
335    n++;
336  }
337  return(rc);
338}
339
340int32_t byte_atob(char *asc)
341{
342  int32_t rc;
343
344  if (strlen(trim(asc))!=2)
345    rc=(-1);
346  else
347    if ((rc=(gethexval(asc[0])<<4)|gethexval(asc[1]))&0x100)
348      rc=(-1);
349  return(rc);
350}
351
352int32_t word_atob(char *asc)
353{
354  int32_t rc;
355
356  if (strlen(trim(asc))!=4)
357    rc=(-1);
358  else
359  {
360    rc=gethexval(asc[0])<<12 | gethexval(asc[1])<<8 |
361       gethexval(asc[2])<<4  | gethexval(asc[3]);
362    if (rc&0x10000)
363      rc=(-1);
364  }
365  return(rc);
366}
367
368/*
369 * dynamic word_atob
370 * converts an 1-4 digit asc hexstring
371 */
372int32_t dyn_word_atob(char *asc)
373{
374    int32_t rc = (-1);
375    int32_t i, len = strlen(trim(asc));
376
377    if (len <= 4 && len > 0) {
378        for(i = 0, rc = 0; i < len; i++)
379            rc = rc << 4 | gethexval(asc[i]);
380
381        if (rc & 0x10000)
382            rc = (-1);
383    }
384    return(rc);
385}
386
387int32_t key_atob_l(char *asc, uchar *bin, int32_t l)
388{
389  int32_t i, n1, n2, rc;
390  for (i=rc=0; i<l; i+=2)
391  {
392    if ((n1=gethexval(asc[]))<0) rc=(-1);
393    if ((n2=gethexval(asc[i+1]))<0) rc=(-1);
394    bin[i>>1]=(n1<<4)+(n2&0xff);
395  }
396  return(rc);
397}
398
399char *cs_hexdump(int32_t m, const uchar *buf, int32_t n)
400{
401    return cs_hexdump_buf(m, buf, n, (char *)cur_client()->dump, sizeof(cur_client()->dump));
402}
403
404char *cs_hexdump_buf(int32_t m, const uchar *buf, int32_t n, char *target, int32_t len)
405{
406  int32_t i = 0;
407
408  target[0]='\0';
409  m=(m)?3:2;
410  if (m*n>=len) n=(len/m)-1;
411  while (i<n){
412    snprintf(target+(m*i), len-(m*i), "%02X%s", *buf++, (m>2)?" ":"");
413    ++i;
414  }
415  return(target);
416}
417
418static int32_t inet_byteorder=0;
419in_addr_t cs_inet_order(in_addr_t n)
420{
421  if (!inet_byteorder)
422    inet_byteorder=((inet_addr("1.2.3.4")+1)==inet_addr("1.2.3.5")) ? 1 : 2;
423  switch (inet_byteorder)
424  {
425    case 1:
426      break;
427    case 2:
428      n=((n&0xff000000) >> 24 ) |
429        ((n&0x00ff0000) >>  8 ) |
430        ((n&0x0000ff00) <<  8 ) |
431        ((n&0x000000ff) << 24 );
432      break;
433  }
434  return(n);
435}
436
437char *cs_inet_ntoa(in_addr_t n)
438{
439  struct in_addr in;
440  in.s_addr=n;
441  return((char *)inet_ntoa(in));
442}
443
444in_addr_t cs_inet_addr(char *txt)
445{
446    return(inet_addr(txt));
447}
448
449
450int32_t check_ip(struct s_ip *ip, in_addr_t n)
451{
452    struct s_ip *p_ip;
453    int32_t ok = 0;
454    for (p_ip=ip; (p_ip) && (!ok); p_ip=p_ip->next)
455        ok=((cs_inet_order(n)>=cs_inet_order(p_ip->ip[0])) && (cs_inet_order(n)<=cs_inet_order(p_ip->ip[1])));
456
457    return ok;
458}
459
460uint32_t b2i(int32_t n, uchar *b)
461{
462  switch(n)
463  {
464    case 2:
465      return ((b[0]<<8) | b[1]);
466    case 3:
467      return ((b[0]<<16) | (b[1]<<8) | b[2]);
468    case 4:
469      return (((b[0]<<24) | (b[1]<<16) | (b[2]<<8) | b[3]) & 0xffffffffL);
470    default:
471      cs_log("Error in b2i, n=%i",n);
472  }
473  return 0;
474}
475
476uint64_t b2ll(int32_t n, uchar *b)
477{
478  int32_t i;
479  uint64_t k=0;
480  for(i=0; i<n; k+=b[i++])
481    k<<=8;
482  return(k);
483}
484
485uchar *i2b_buf(int32_t n, uint32_t i, uchar *b)
486{
487  switch(n)
488  {
489    case 2:
490      b[0]=(i>> 8) & 0xff;
491      b[1]=(i    ) & 0xff;
492      break;
493    case 3:
494      b[0]=(i>>16) & 0xff;
495      b[1]=(i>> 8) & 0xff;
496      b[2]=(i    ) & 0xff;
497    case 4:
498      b[0]=(i>>24) & 0xff;
499      b[1]=(i>>16) & 0xff;
500      b[2]=(i>> 8) & 0xff;
501      b[3]=(i    ) & 0xff;
502      break;
503  }
504  return(b);
505}
506
507uint32_t a2i(char *asc, int32_t bytes)
508{
509  int32_t i, n;
510  uint32_t rc;
511  for (rc=i=0, n=strlen(trim(asc))-1; i<(abs(bytes)<<1); n--, i++)
512    if (n>=0)
513    {
514      int32_t rcl;
515      if ((rcl=gethexval(asc[n]))<0)
516      {
517        errno=EINVAL;
518        return(0x1F1F1F);
519      }
520      rc|=(rcl<<(i<<2));
521    }
522    else
523      if (bytes<0)
524        rc|=(0xf<<(i<<2));
525  errno=0;
526  return(rc);
527}
528
529int32_t boundary(int32_t exp, int32_t n)
530{
531  return((((n-1)>>exp)+1)<<exp);
532}
533
534void cs_ftime(struct timeb *tp)
535{
536#ifdef NO_FTIME
537  struct timeval tv;
538  gettimeofday(&tv, (struct timezone *)0);
539  tp->time=tv.tv_sec;
540  tp->millitm=tv.tv_usec/1000;
541#else
542  ftime(tp);
543#endif
544}
545
546void cs_sleepms(uint32_t msec)
547{
548    //does not interfere with signals like sleep and usleep do
549    struct timespec req_ts;
550    req_ts.tv_sec = msec/1000;
551    req_ts.tv_nsec = (msec % 1000) * 1000000L;
552    nanosleep (&req_ts, NULL);
553}
554
555void cs_sleepus(uint32_t usec)
556{
557    //does not interfere with signals like sleep and usleep do
558    struct timespec req_ts;
559    req_ts.tv_sec = usec/1000000;
560    req_ts.tv_nsec = (usec % 1000000) * 1000L;
561    nanosleep (&req_ts, NULL);
562}
563
564#ifdef OS_CYGWIN32
565#include <windows.h>
566void cs_setpriority(int32_t prio)
567{
568  HANDLE WinId;
569  uint32_t wprio;
570  switch((prio+20)/10)
571  {
572    case  0: wprio=REALTIME_PRIORITY_CLASS; break;
573    case  1: wprio=HIGH_PRIORITY_CLASS;     break;
574    case  2: wprio=NORMAL_PRIORITY_CLASS;   break;
575    default: wprio=IDLE_PRIORITY_CLASS;     break;
576  }
577  WinId=GetCurrentProcess();
578  SetPriorityClass(WinId, wprio);
579}
580#else
581void cs_setpriority(int32_t prio)
582{
583#ifdef PRIO_PROCESS
584  setpriority(PRIO_PROCESS, 0, prio);  // ignore errors
585#endif
586}
587#endif
588
589/* Checks an array if it is filled (a value > 0) and returns the last position (1...length) where something was found.
590   length specifies the maximum length to check for. */
591int32_t check_filled(uchar *value, int32_t length){
592    if(value == NULL) return 0;
593    int32_t i, j = 0;
594    for (i = 0; i < length; ++i){
595        if(value[i] > 0) j = i + 1;
596    }
597    return j;
598}
599
600/* This function encapsulates malloc. It automatically adds an error message to the log if it failed and calls cs_exit(quiterror) if quiterror > -1.
601   result will be automatically filled with the new memory position or NULL on failure. */
602void *cs_malloc(void *result, size_t size, int32_t quiterror){
603    void **tmp = (void *)result;
604    *tmp = malloc (size);
605    if(*tmp == NULL){
606        cs_log("Couldn't allocate memory (errno=%d %s)!", errno, strerror(errno));
607        if(quiterror > -1) cs_exit(quiterror);
608    } else {
609        memset(*tmp, 0, size);
610    }
611    return *tmp;
612}
613
614/* This function encapsulates realloc. It automatically adds an error message to the log if it failed and calls cs_exit(quiterror) if quiterror > -1.
615    result will be automatically filled with the new memory position or NULL on failure. If a failure occured, the existing memory in result will be freed. */
616void *cs_realloc(void *result, size_t size, int32_t quiterror){
617    void **tmp = (void *)result, **tmp2 = (void *)result;
618    *tmp = realloc (*tmp, size);
619    if(*tmp == NULL){
620        cs_log("Couldn't allocate memory (errno=%d %s)!", errno, strerror(errno));
621        free(*tmp2);
622        if(quiterror > -1) cs_exit(quiterror);
623    }
624    return *tmp;
625}
626
627#ifdef WEBIF
628/* Converts a char to it's hex representation. See urlencode and char_to_hex on how to use it.*/
629char to_hex(char code){
630    static const char hex[] = "0123456789abcdef";
631    return hex[(int)code & 15];
632}
633
634/* Converts a char array to a char array with hex values (needed for example for md5).
635    Note that result needs to be at least (p_array_len * 2) + 1 large. */
636void char_to_hex(const unsigned char* p_array, uint32_t p_array_len, unsigned char *result) {
637    result[p_array_len*2] = '\0';
638    const unsigned char* p_end = p_array + p_array_len;
639    uint32_t pos=0;
640    const unsigned char* p;
641    for( p = p_array; p != p_end; p++, pos+=2 ) {
642        result[pos] = to_hex(*p >> 4);
643        result[pos+1] = to_hex(*p & 15);
644    }
645}
646
647/* Creates a random string with specified length. Note that dst must be one larger than size to hold the trailing \0*/
648void create_rand_str(char *dst, int32_t size){
649    int32_t i;
650    for (i = 0; i < size; ++i){
651        dst[i] = (rand() % 94) + 32;
652    }
653    dst[i] = '\0';
654}
655#endif
656
657/* Return 1 if the file exists, else 0 */
658int32_t file_exists(const char * filename){
659    FILE *file;
660    if ((file = fopen(filename, "r"))){
661        fclose(file);
662        return 1;
663    }
664    return 0;
665}
666
667/* Clears the s_ip structure provided. The pointer will be set to NULL so everything is cleared.*/
668void clear_sip(struct s_ip **sip){
669    struct s_ip *cip = *sip;
670    for (*sip = NULL; cip != NULL; cip = cip->next){
671        add_garbage(cip);
672    }
673}
674
675/* Clears the s_ftab struct provided by setting nfilts and nprids to zero. */
676void clear_ftab(struct s_ftab *ftab){
677    int32_t i, j;
678    for (i = 0; i < CS_MAXFILTERS; i++) {
679        ftab->filts[i].caid = 0;
680        for (j = 0; j < CS_MAXPROV; j++)
681            ftab->filts[i].prids[j] = 0;
682        ftab->filts[i].nprids = 0;
683    }
684    ftab->nfilts = 0;
685}
686
687/* Clears the s_ptab struct provided by setting nfilts and nprids to zero. */
688void clear_ptab(struct s_ptab *ptab){
689    int32_t i = ptab->nports;
690    ptab->nports = 0;
691    for (; i >= 0; --i) {
692        ptab->ports[i].ftab.nfilts = 0;
693        ptab->ports[i].ftab.filts[0].nprids = 0;
694    }   
695}
696
697/* Clears given caidtab */
698void clear_caidtab(struct s_caidtab *ctab){
699    memset(ctab, 0, sizeof(struct s_caidtab));
700    int32_t i;
701    for (i = 1; i < CS_MAXCAIDTAB; ctab->mask[i++] = 0xffff);
702}
703
704/* Clears given tuntab */
705void clear_tuntab(struct s_tuntab *ttab){
706    memset(ttab, 0, sizeof(struct s_tuntab));
707}
708
709/* Copies a file from srcfile to destfile. If an error occured before writing, -1 is returned, else -2. On success, 0 is returned.*/
710int32_t file_copy(char *srcfile, char *destfile){
711    FILE *src, *dest;
712  int32_t ch;
713  if((src = fopen(srcfile, "r"))==NULL) {
714    cs_log("Error opening file %s for reading (errno=%d %s)!", srcfile, errno, strerror(errno));
715    return(-1);
716  }
717  if((dest = fopen(destfile, "w"))==NULL) {
718    cs_log("Error opening file %s for writing (errno=%d %s)!", destfile, errno, strerror(errno));
719    fclose(src);
720    return(-1);
721  }
722
723    while(1){
724        ch = fgetc(src);
725        if(ch==EOF){
726            break;
727        }   else {
728            fputc(ch, dest);
729            if(ferror(dest)) {
730                cs_log("Error while writing to file %s (errno=%d %s)!", destfile, errno, strerror(errno));
731                fclose(src);
732                fclose(dest);
733                return(-2);
734            }
735        }
736    }
737    fclose(src);
738    fclose(dest);
739    return(0);
740}
741
742/* Overwrites destfile with tmpfile. If forceBakOverWrite = 0, the bakfile will not be overwritten if it exists, else it will be.*/
743int32_t safe_overwrite_with_bak(char *destfile, char *tmpfile, char *bakfile, int32_t forceBakOverWrite){
744    int32_t rc;
745    if (file_exists(destfile)) {
746        if(forceBakOverWrite != 0 || !file_exists(bakfile)){
747            if(file_copy(destfile, bakfile) < 0){
748                cs_log("Error copying original config file %s to %s. The original config will be left untouched!", destfile, bakfile);
749                if(remove(tmpfile) < 0) cs_log("Error removing temp config file %s (errno=%d %s)!", tmpfile, errno, strerror(errno));
750                return(1);
751            }
752        }
753    }
754    if((rc = file_copy(tmpfile, destfile)) < 0){
755        cs_log("An error occured while writing the new config file %s.", destfile);
756        if(rc == -2) cs_log("The config will be missing or only partly filled upon next startup as this is a non-recoverable error! Please restore from backup or try again.", destfile);
757        if(remove(tmpfile) < 0) cs_log("Error removing temp config file %s (errno=%d %s)!", tmpfile, errno, strerror(errno));
758        return(1);
759    }
760    if(remove(tmpfile) < 0) cs_log("Error removing temp config file %s (errno=%d %s)!", tmpfile, errno, strerror(errno));
761    return(0);
762}
763
764/* Replacement of fprintf which adds necessary whitespace to fill up the varname to a fixed width.
765   If varname is longer than varnameWidth, no whitespace is added*/
766void fprintf_conf(FILE *f, int32_t varnameWidth, const char *varname, const char *fmtstring, ...){
767    int32_t varlen = strlen(varname);
768    int32_t max = (varlen > varnameWidth) ? varlen : varnameWidth;
769    char varnamebuf[max + 3];
770    char *ptr = varnamebuf + varlen;
771    va_list argptr;
772
773    cs_strncpy(varnamebuf, varname, sizeof(varnamebuf));
774    while(varlen < varnameWidth){
775        ptr[0] = ' ';
776        ++ptr;
777        ++varlen;
778    }
779    cs_strncpy(ptr, "= ", sizeof(varnamebuf)-(ptr-varnamebuf));
780    if (fwrite(varnamebuf, sizeof(char), strlen(varnamebuf), f)){
781        if(strlen(fmtstring) > 0){
782            va_start(argptr, fmtstring);
783            vfprintf(f, fmtstring, argptr);
784            va_end(argptr);
785        }
786    }
787}
788
789/* Ordinary strncpy does not terminate the string if the source is exactly as long or longer as the specified size. This can raise security issues.
790   This function is a replacement which makes sure that a \0 is always added. num should be the real size of char array (do not subtract -1). */
791void cs_strncpy(char * destination, const char * source, size_t num){
792    uint32_t l, size = strlen(source);
793    if(size > num - 1) l = num - 1;
794    else l = size;
795    memcpy(destination, source, l);
796    destination[l] = '\0';
797}
798
799/* This function is similar to strncpy but is case insensitive when comparing. */
800int32_t cs_strnicmp(const char * str1, const char * str2, size_t num){
801    uint32_t i, len1 = strlen(str1), len2 = strlen(str2);
802    int32_t diff;
803    for(i = 0; i < len1 && i < len2 && i < num; ++i){
804        diff = toupper(str1[i]) - toupper(str2[i]);
805        if (diff != 0) return diff;
806    }
807    return 0;
808}
809
810/* Converts the string txt to it's lower case representation. */
811char *strtolower(char *txt){
812  char *p;
813  for (p=txt; *p; p++)
814    if (isupper((uchar)*p)) *p=tolower((uchar)*p);
815  return(txt);
816}
817
818/* Allocates a new empty string and copies str into it. You need to free() the result. */
819char *strnew(char *str){
820  if (!str)
821    return NULL;
822   
823  char *newstr = cs_malloc(&newstr, strlen(str)+1, 1);
824  cs_strncpy(newstr, str, strlen(str)+1);
825 
826  return newstr;
827}
828
829/* Gets the servicename. Make sure that buf is at least 32 bytes large. */
830char *get_servicename(struct s_client *cl, int32_t srvid, int32_t caid, char *buf){
831    int32_t i;
832    struct s_srvid *this;
833    buf[0] = '\0';
834
835    if (!srvid)
836        return(buf);
837
838    if (cl && cl->last_srvidptr && cl->last_srvidptr->srvid==srvid)
839        for (i=0; i < cl->last_srvidptr->ncaid; i++)
840            if (cl->last_srvidptr->caid[i] == caid && cl->last_srvidptr->name){
841                cs_strncpy(buf, cl->last_srvidptr->name, 32);
842                return(buf);
843            }
844
845    for (this = cfg.srvid[srvid>>12]; this && (!buf[0]); this = this->next)
846        if (this->srvid == srvid)
847            for (i=0; i < this->ncaid; i++)
848                if (this->caid[i] == caid && this->name) {
849                    cs_strncpy(buf, this->name, 32);
850                    cl->last_srvidptr = this;
851                    return(buf);
852                }
853
854    if (!buf[0]) {
855        snprintf(buf, 32, "%04X:%04X unknown", caid, srvid);
856        cl->last_srvidptr = NULL;
857    }
858    return(buf);
859}
860
861/* Gets the tier name. Make sure that buf is at least 83 bytes long. */
862char *get_tiername(int32_t tierid, int32_t caid, char *buf){
863    int32_t i;
864    struct s_tierid *this = cfg.tierid;
865
866    for (buf[0] = 0; this && (!buf[0]); this = this->next)
867        if (this->tierid == tierid)
868            for (i=0; i<this->ncaid; i++)
869                if (this->caid[i] == caid)
870                    cs_strncpy(buf, this->name, 32);
871
872    //if (!name[0]) sprintf(name, "%04X:%04X unknown", caid, tierid);
873    if (!tierid) buf[0] = '\0';
874    return(buf);
875}
876
877/* Gets the provider name. Make sure that buf is at least 83 bytes long. */
878char *get_provider(int32_t caid, uint32_t provid, char *buf){
879    struct s_provid *this = cfg.provid;
880
881    for (buf[0] = 0; this && (!buf[0]); this = this->next) {
882        if (this->caid == caid && this->provid == provid) {
883            snprintf(buf, 83, "%s", this->prov);
884            if (this->sat[0]) {
885                strcat(buf, " / ");
886                strcat(buf, this->sat);
887            }
888            if (this->lang[0]) {
889                strcat(buf, " / ");
890                strcat(buf, this->lang);
891            }
892        }
893    }
894
895    if (!buf[0]) snprintf(buf, 83, "%04X:%06X unknown", caid, provid);
896    if (!caid) buf[0] = '\0';
897    return(buf);
898}
899
900void make_non_blocking(int32_t fd) {
901    int32_t fl;
902    fl=fcntl(fd, F_GETFL);
903    fcntl(fd, F_SETFL, fl | O_NONBLOCK | O_NDELAY);
904}
905
906uint32_t seed;
907
908/* A fast random number generator. Depends on initialization of seed from init_rnd().
909   Only use this if you don't need good random numbers (so don't use in security critical situations). */
910uchar fast_rnd() {
911    uint32_t offset = 12923;
912    uint32_t multiplier = 4079;
913
914    seed = seed * multiplier + offset;
915    return (uchar) (seed % 0xFF);
916}
917
918/* Initializes the random number generator and the seed for the fast_rnd() function. */
919void init_rnd() {
920    srand((uint32_t)time((time_t *)NULL));
921    seed = (uint32_t) time((time_t*)0);
922}
923
924int32_t hexserialset(struct s_reader *rdr)
925{
926    int32_t i;
927
928    if (!rdr) return 0;
929
930    for (i = 0; i < 8; i++)
931        if (rdr->hexserial[i])
932            return 1;
933    return 0;
934}
935
936static char *netw_ext_prot[] = { "cccam", "cccam ext", "newcamd524" };
937
938char *reader_get_type_desc(struct s_reader * rdr, int32_t extended __attribute__((unused)))
939{
940    static char *typtxt[] = { "unknown", "mouse", "mouse", "sc8in1", "mp35", "mouse", "internal", "smartreader", "pcsc" };
941    char *desc = typtxt[0];
942
943    if (rdr->crdr.active==1)
944        return rdr->crdr.desc;
945
946    if (rdr->typ & R_IS_NETWORK) {
947        if (rdr->ph.desc)
948            desc = rdr->ph.desc;
949    } else {
950        desc = typtxt[rdr->typ];
951    }
952
953    if ((rdr->typ == R_NEWCAMD) && (rdr->ncd_proto == NCD_524))
954        desc = netw_ext_prot[2];
955
956#ifdef MODULE_CCCAM
957    else if (rdr->typ == R_CCCAM) {
958        desc = netw_ext_prot[0];
959        struct s_client *cl = rdr->client;
960        if (cl) {
961            struct cc_data *cc = cl->cc;
962            if (cc && cc->extended_mode)
963                desc = netw_ext_prot[extended];
964        }
965    }
966#endif
967
968    return (desc);
969}
970
971char *monitor_get_proto(struct s_client *cl)
972{
973    char *ctyp;
974    switch(cl->typ) {
975        case 's'    : ctyp = "server"; break;
976        case 'h'    : ctyp = "http"; break;
977        case 'p'    :
978        case 'r'    : ctyp = reader_get_type_desc(cl->reader, 1); break;
979#ifdef CS_ANTICASC
980        case 'a'    : ctyp = "anticascader"; break;
981#endif
982#ifdef MODULE_CCCAM
983        case 'c'    :
984            if (cl->cc && ((struct cc_data *)cl->cc)->extended_mode) {
985                ctyp = netw_ext_prot[1];
986                break;
987            }
988#endif
989        default     : ctyp = ph[cl->ctyp].desc;
990    }
991    return(ctyp);
992}
993
994/*
995 * resolve clienttype for newcamdprotocol
996 */
997char *get_ncd_client_name(char *client_id)
998{
999        static const int32_t max_id_idx = 32;
1000        static const char const *ncd_service_ids[] = { "0000", "5644", "4C43", "4333", "7264", "6762", "6D67", "7763", "6E73", "6378", "6B61",
1001                                           "6576", "4343", "5456", "414C", "0666", "0667", "9911", "434C", "4765", "5342",
1002                                           "6E65", "4E58", "4453", "8888", "7363", "0669", "0665", "0769", "4543", "6D63",
1003                                           "6B63", "6502" };
1004
1005        static char *ncd_service_names[] = { "generic", "vdr-sc", "LCE", "camd3", "radegast", "gbox2CS", "mgcamd", //actually a const so threadsafe
1006                                             "WinCSC", "NewCS", "cx", "Kaffeine", "evocamd", "CCcam", "Tecview",
1007                                             "AlexCS", "rqcamd", "rq-echo-client", "ACamd", "Cardlink", "Octagon", "SBCL",
1008                                             "NextYE2k", "NextYE2k", "DiabloCam/UW", "OSCam", "Scam", "rq-sssp-client/CW",
1009                                             "rq-sssp-client/CS", "JlsRq", "eyetvCamd", "mpcs", "kpcs", "Tvheadend", "unknown - please report" };
1010
1011        int32_t idx = 0;
1012        for (idx = 0; idx <= max_id_idx; idx++) {
1013        if(!memcmp(ncd_service_ids[idx], client_id, 4))
1014                        return ncd_service_names[idx];
1015
1016        }
1017
1018        return ncd_service_names[max_id_idx+1];
1019}
1020
1021
1022void hexserial_to_newcamd(uchar *source, uchar *dest, uint16_t caid)
1023{
1024  caid = caid >> 8;
1025  if ((caid == 0x17) || (caid == 0x06))    // Betacrypt or Irdeto
1026  {
1027    // only 4 Bytes Hexserial for newcamd clients (Hex Base + Hex Serial)
1028    // first 2 Byte always 00
1029    dest[0]=0x00; //serial only 4 bytes
1030    dest[1]=0x00; //serial only 4 bytes
1031    // 1 Byte Hex Base (see reader-irdeto.c how this is stored in "source")
1032    dest[2]=source[3];
1033    // 3 Bytes Hex Serial (see reader-irdeto.c how this is stored in "source")
1034    dest[3]=source[0];
1035    dest[4]=source[1];
1036    dest[5]=source[2];
1037  }
1038  else if ((caid == 0x05) || (caid == 0x0D))
1039  {
1040    dest[0] = 0x00;
1041    memcpy(dest+1, source, 5);
1042  }
1043  else
1044    memcpy(dest, source, 6);
1045}
1046
1047void newcamd_to_hexserial(uchar *source, uchar *dest, uint16_t caid)
1048{
1049  caid = caid >> 8;
1050  if ((caid == 0x17) || (caid == 0x06)) {
1051    memcpy(dest, source+3, 3);
1052    dest[3] = source[2];
1053        dest[4] = 0;
1054        dest[5] = 0;
1055  }
1056  else if ((caid == 0x05) || (caid == 0x0D)) {
1057    memcpy(dest, source+1, 5);
1058        dest[5] = 0;
1059    }
1060  else
1061    memcpy(dest, source, 6);
1062}
1063
1064/* Internal function of cs_lock and cs_trylock to prepare adding an entry to the list. Do not call this externally. */
1065#ifdef WITH_MUTEXDEBUG
1066struct s_client* cs_preparelock(struct s_client *cl, pthread_mutex_t *mutex, char *file, uint16_t line){
1067#else
1068struct s_client* cs_preparelock(struct s_client *cl, pthread_mutex_t *mutex){
1069#endif
1070    if(cl){
1071        // WebIf doesn't have real clients...
1072        if(cl->typ == 'h') return NULL;
1073        if(cl->mutexstore_alloc <= cl->mutexstore_used){
1074            void *ret;
1075#ifdef WITH_MUTEXDEBUG
1076            void *ret2, *ret3;
1077#endif
1078            if(cl->mutexstore_alloc == 0){
1079                ret = cs_malloc(&cl->mutexstore, 8 * sizeof(pthread_mutex_t *), -1);
1080#ifdef WITH_MUTEXDEBUG
1081                ret2 = cs_malloc(&cl->mutexstore_file, 8 * sizeof(char *), -1);
1082                ret3 = cs_malloc(&cl->mutexstore_line, 8 * sizeof(uint16_t *), -1);
1083#endif
1084            } else {
1085                ret = cs_realloc(&cl->mutexstore, (cl->mutexstore_used + 8) * sizeof(pthread_mutex_t *), -1);
1086#ifdef WITH_MUTEXDEBUG
1087                ret2 = cs_realloc(&cl->mutexstore_file, (cl->mutexstore_used + 8) * sizeof(char *), -1);
1088                ret3 = cs_realloc(&cl->mutexstore_line, (cl->mutexstore_used + 8) * sizeof(uint16_t *), -1);
1089#endif
1090            }
1091#ifdef WITH_MUTEXDEBUG
1092            if(ret != NULL && ret2 != NULL && ret3 != NULL){
1093#else
1094            if(ret != NULL){
1095#endif
1096                cl->mutexstore_alloc = cl->mutexstore_used + 8;     
1097                cl->mutexstore[cl->mutexstore_used] = mutex;
1098#ifdef WITH_MUTEXDEBUG
1099                cl->mutexstore_file[cl->mutexstore_used] = file;
1100                cl->mutexstore_line[cl->mutexstore_used] = line;
1101#endif
1102            } else {
1103                cl->mutexstore_alloc = 0;
1104                cl->mutexstore_used = 0;
1105#ifdef WITH_MUTEXDEBUG
1106                NULLFREE(cl->mutexstore);
1107                NULLFREE(cl->mutexstore_file);
1108                NULLFREE(cl->mutexstore_line);
1109#endif
1110            }
1111        } else {
1112            cl->mutexstore[cl->mutexstore_used] = mutex;           
1113        }
1114    }
1115    return cl;
1116}
1117
1118/* Replacement for pthread_mutex_lock. Locks are saved to the client structure so that they can get cleaned up if the thread was interrupted while holding a lock. */
1119#ifdef WITH_MUTEXDEBUG
1120int32_t cs_lock_debug(pthread_mutex_t *mutex, char *file, uint16_t line){
1121#else
1122int32_t cs_lock(pthread_mutex_t *mutex){
1123#endif
1124    int32_t result, oldtype;
1125    /* Make sure that we won't get interrupted while getting the lock */
1126    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);
1127#ifdef WITH_MUTEXDEBUG
1128    uint16_t i = 0;
1129    struct s_client *cl = cs_preparelock(cur_client(), mutex, file, line);
1130    while((result = pthread_mutex_trylock(mutex)) == EBUSY && i < 1000){
1131        pthread_testcancel();
1132        cs_sleepms(5);
1133        ++i;
1134    }
1135    if(result == 0 && cl)
1136        cl->mutexstore_used++;
1137    else if(result == EBUSY){
1138        cs_log("Couldn't obtain lock within 5s in: %s, line %u.", file, line);
1139#else
1140    struct s_client *cl = cs_preparelock(cur_client(), mutex);
1141    if((result = pthread_mutex_lock(mutex)) == 0 && cl){
1142        cl->mutexstore_used++;
1143#endif
1144    }
1145    pthread_setcanceltype(oldtype, NULL);
1146    pthread_testcancel();
1147    return result;
1148}
1149
1150/* Encapsulates pthread_mutex_trylock. If a lock is gained it is saved to the client structure so that it can get cleaned up if the thread was interrupted while holding a lock. */
1151#ifdef WITH_MUTEXDEBUG
1152int32_t cs_trylock_debug(pthread_mutex_t *mutex, char *file, uint16_t line){
1153#else
1154int32_t cs_trylock(pthread_mutex_t *mutex){
1155#endif
1156    int32_t result, oldtype;
1157    /* Make sure that we won't get interrupted while getting the lock */
1158    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);
1159    if((result=pthread_mutex_trylock(mutex)) == 0){
1160#ifdef WITH_MUTEXDEBUG
1161        struct s_client *cl = cs_preparelock(cur_client(), mutex, file, line);
1162#else
1163        struct s_client *cl = cs_preparelock(cur_client(), mutex);
1164#endif
1165        if(cl)
1166            cl->mutexstore_used++;
1167    }
1168    pthread_setcanceltype(oldtype, NULL);
1169    pthread_testcancel();
1170    return result;
1171}
1172
1173/* Encapsulates pthread_mutex_unlock and removes the given mutex from the client structure
1174  If the given lock was not previously locked by the current thread, nothing is done. */
1175#ifdef WITH_MUTEXDEBUG
1176int32_t cs_unlock_debug(pthread_mutex_t *mutex, char *file, uint16_t line){
1177#else
1178int32_t cs_unlock(pthread_mutex_t *mutex){
1179#endif
1180    struct s_client *cl = cur_client(); 
1181    if(cl && cl->typ != 'h'){
1182        uint16_t i;
1183        /* new mutexes get appended to the end so it should be more efficient to search from end to beginning */
1184        for(i = cl->mutexstore_used; i > 0; --i){
1185            if(cl->mutexstore[i - 1] == mutex){
1186                int32_t result, oldtype;
1187                /* Make sure that we won't get interrupted while returning the lock */
1188                pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);
1189                if(i < cl->mutexstore_used){
1190                    // Move mutex to last position to prepare removal
1191                    do {
1192                        cl->mutexstore[i - 1] = cl->mutexstore[i];
1193                        ++i;
1194                    } while (i < cl->mutexstore_used);
1195                    cl->mutexstore[cl->mutexstore_used - 1] = mutex;
1196                }   
1197                if((result=pthread_mutex_unlock(mutex)) == 0)
1198                    cl->mutexstore_used--;
1199                pthread_setcanceltype(oldtype, NULL);
1200                pthread_testcancel();
1201                return result;
1202            }
1203        }
1204#ifdef WITH_MUTEXDEBUG
1205        cs_log("Couldn't find mutex to unlock from: %s, %u", file, line);
1206#endif
1207        return EINVAL;
1208    }   else return pthread_mutex_unlock(mutex);
1209}
1210
1211/* Releases all locks still held by the current client. */
1212void cs_cleanlocks(){
1213    struct s_client *cl = cur_client();
1214    if(cl && cl->mutexstore_alloc > 0){
1215        uint16_t i;     
1216        for(i = 0; i < cl->mutexstore_used; ++i){
1217            pthread_mutex_unlock(cl->mutexstore[i]);
1218#ifdef WITH_MUTEXDEBUG
1219            cs_log("Cleaned up lock from: %s, line %u.", cl->mutexstore_file[i], cl->mutexstore_line[i]);
1220#endif
1221        }
1222        cl->mutexstore_used = 0;
1223        cl->mutexstore_alloc = 0;
1224        free(cl->mutexstore);
1225    }
1226}
1227
1228/* Returns the ip from the given hostname. If gethostbyname is configured in the config file, a lock
1229   will be held until the ip has been resolved. */
1230uint32_t cs_getIPfromHost(const char *hostname){
1231    uint32_t result = 0;
1232    //Resolve with gethostbyname:
1233    if (cfg.resolve_gethostbyname) {
1234        cs_lock(&gethostbyname_lock);
1235        struct hostent *rht = gethostbyname(hostname);
1236        if (!rht)
1237            cs_log("can't resolve %s", hostname);
1238        else
1239            result=((struct in_addr*)rht->h_addr)->s_addr;
1240        cs_unlock(&gethostbyname_lock);
1241    }   else { //Resolve with getaddrinfo:
1242        struct addrinfo hints, *res = NULL;
1243        memset(&hints, 0, sizeof(hints));
1244        hints.ai_socktype = SOCK_STREAM;
1245        hints.ai_family = AF_INET;
1246        hints.ai_protocol = IPPROTO_TCP;
1247
1248        int32_t err = getaddrinfo(hostname, NULL, &hints, &res);
1249        if (err != 0 || !res || !res->ai_addr) {
1250            cs_log("can't resolve %s, error: %s", hostname, err ? gai_strerror(err) : "unknown");
1251        } else {
1252            result=((struct sockaddr_in *)(res->ai_addr))->sin_addr.s_addr;
1253        }
1254        if (res) freeaddrinfo(res);
1255    }
1256    return result;
1257}
Note: See TracBrowser for help on using the repository browser.