From 3de927e157624a9f39fa4146b1fcf624be29e48d Mon Sep 17 00:00:00 2001 From: mardock2009 Date: Tue, 24 Feb 2026 21:37:51 +0000 Subject: [PATCH] file-permission-fix --- .gitignore | 0 .gitmodules | 0 CMakeLists.txt | 0 CODING.RULES.txt | 0 COPYING | 0 Distribution/doc/example/oscam.ac | 0 Distribution/doc/example/oscam.cacheex | 0 Distribution/doc/example/oscam.cert | 0 Distribution/doc/example/oscam.conf | 0 Distribution/doc/example/oscam.dvbapi | 0 Distribution/doc/example/oscam.guess | 0 Distribution/doc/example/oscam.ird | 0 Distribution/doc/example/oscam.provid | 0 Distribution/doc/example/oscam.server | 0 Distribution/doc/example/oscam.services | 0 Distribution/doc/example/oscam.srvid | 0 Distribution/doc/example/oscam.tiers | 0 Distribution/doc/example/oscam.user | 0 Distribution/doc/example/oscam.whitelist | 0 Distribution/doc/html/list_smargo.1.html | 0 Distribution/doc/html/oscam.1.html | 0 Distribution/doc/html/oscam.ac.5.html | 0 Distribution/doc/html/oscam.cacheex.5.html | 0 Distribution/doc/html/oscam.cert.5.html | 0 Distribution/doc/html/oscam.conf.5.html | 0 Distribution/doc/html/oscam.dvbapi.5.html | 0 Distribution/doc/html/oscam.guess.5.html | 0 Distribution/doc/html/oscam.ird.5.html | 0 Distribution/doc/html/oscam.provid.5.html | 0 Distribution/doc/html/oscam.ratelimit.5.html | 0 Distribution/doc/html/oscam.server.5.html | 0 Distribution/doc/html/oscam.services.5.html | 0 Distribution/doc/html/oscam.srvid.5.html | 0 Distribution/doc/html/oscam.srvid2.5.html | 0 Distribution/doc/html/oscam.tiers.5.html | 0 Distribution/doc/html/oscam.user.5.html | 0 Distribution/doc/html/oscam.whitelist.5.html | 0 Distribution/doc/man/list_smargo.1 | 0 Distribution/doc/man/oscam.1 | 0 Distribution/doc/man/oscam.ac.5 | 0 Distribution/doc/man/oscam.cacheex.5 | 0 Distribution/doc/man/oscam.cert.5 | 0 Distribution/doc/man/oscam.conf.5 | 0 Distribution/doc/man/oscam.dvbapi.5 | 0 Distribution/doc/man/oscam.guess.5 | 0 Distribution/doc/man/oscam.ird.5 | 0 Distribution/doc/man/oscam.provid.5 | 0 Distribution/doc/man/oscam.ratelimit.5 | 0 Distribution/doc/man/oscam.server.5 | 0 Distribution/doc/man/oscam.services.5 | 0 Distribution/doc/man/oscam.srvid.5 | 0 Distribution/doc/man/oscam.srvid2.5 | 0 Distribution/doc/man/oscam.tiers.5 | 0 Distribution/doc/man/oscam.user.5 | 0 Distribution/doc/man/oscam.whitelist.5 | 0 Distribution/doc/txt/list_smargo.txt | 0 Distribution/doc/txt/oscam.ac.txt | 0 Distribution/doc/txt/oscam.cacheex.txt | 0 Distribution/doc/txt/oscam.cert.txt | 0 Distribution/doc/txt/oscam.conf.txt | 0 Distribution/doc/txt/oscam.dvbapi.txt | 0 Distribution/doc/txt/oscam.guess.txt | 0 Distribution/doc/txt/oscam.ird.txt | 0 Distribution/doc/txt/oscam.provid.txt | 0 Distribution/doc/txt/oscam.ratelimit.txt | 0 Distribution/doc/txt/oscam.server.txt | 0 Distribution/doc/txt/oscam.services.txt | 0 Distribution/doc/txt/oscam.srvid.txt | 0 Distribution/doc/txt/oscam.srvid2.txt | 0 Distribution/doc/txt/oscam.tiers.txt | 0 Distribution/doc/txt/oscam.txt | 0 Distribution/doc/txt/oscam.user.txt | 0 Distribution/doc/txt/oscam.whitelist.txt | 0 Distribution/monitor/mpcsmon-src-0.6.tar.bz2 | Bin Distribution/monitor/mpcsmon.sh | 0 Makefile | 0 Makefile.extra | 0 README.build | 0 README.config | 0 README.dvbapi_protocol | 0 README.md | 0 SoftCam.Key | 0 caid, | 0 config.h | 0 config.mak | 0 config.sh | 0 cscrypt/CMakeLists.txt | 0 cscrypt/Makefile | 0 cscrypt/aes.c | 0 cscrypt/aes.h | 0 cscrypt/bn.h | 0 cscrypt/bn_add.c | 0 cscrypt/bn_asm.c | 0 cscrypt/bn_ctx.c | 0 cscrypt/bn_div.c | 0 cscrypt/bn_exp.c | 0 cscrypt/bn_lcl.h | 0 cscrypt/bn_lib.c | 0 cscrypt/bn_mul.c | 0 cscrypt/bn_print.c | 0 cscrypt/bn_shift.c | 0 cscrypt/bn_sqr.c | 0 cscrypt/bn_word.c | 0 cscrypt/buffer.h | 0 cscrypt/des.c | 0 cscrypt/des.h | 0 cscrypt/fast_aes.c | 0 cscrypt/fast_aes.h | 0 cscrypt/i_cbc.c | 0 cscrypt/i_ecb.c | 0 cscrypt/i_skey.c | 0 cscrypt/idea.h | 0 cscrypt/idea_lcl.h | 0 cscrypt/md5.c | 0 cscrypt/md5.h | 0 cscrypt/mdc2.c | 0 cscrypt/mdc2.h | 0 cscrypt/mem.c | 0 cscrypt/openssl_mods.h | 0 cscrypt/rc6.c | 0 cscrypt/rc6.h | 0 cscrypt/sha1.c | 0 cscrypt/sha1.h | 0 cscrypt/sha256.c | 0 cscrypt/sha256.h | 0 csctapi/CMakeLists.txt | 0 csctapi/Makefile | 0 csctapi/atr.c | 0 csctapi/atr.h | 0 csctapi/cardreaders.h | 0 csctapi/icc_async.c | 0 csctapi/icc_async.h | 0 csctapi/ifd_amsmc.c | 0 csctapi/ifd_azbox.c | 0 csctapi/ifd_cool.c | 0 csctapi/ifd_db2com.c | 0 csctapi/ifd_db2com.h | 0 csctapi/ifd_drecas.c | 0 csctapi/ifd_drecas.h | 0 csctapi/ifd_mp35.c | 0 csctapi/ifd_pcsc.c | 0 csctapi/ifd_phoenix.c | 0 csctapi/ifd_phoenix.h | 0 csctapi/ifd_sc8in1.c | 0 csctapi/ifd_sci.c | 0 csctapi/ifd_sci_global.h | 0 csctapi/ifd_sci_ioctl.h | 0 csctapi/ifd_smargo.c | 0 csctapi/ifd_smartreader.c | 0 csctapi/ifd_smartreader_types.h | 0 csctapi/ifd_stapi.c | 0 csctapi/ifd_stinger.c | 0 csctapi/io_serial.c | 0 csctapi/io_serial.h | 0 csctapi/protocol_t0.c | 0 csctapi/protocol_t0.h | 0 csctapi/protocol_t1.c | 0 devtools/README | 0 devtools/check_cmdline_opts.sh | 0 devtools/check_config_tables.sh | 0 devtools/extract_config.sh | 0 extapi/README | 0 extapi/coolapi.h | 0 extapi/cygwin/SCardErr.h | 0 extapi/cygwin/WinSCard.h | 0 extapi/cygwin/WinSmCrd.h | 0 extapi/linux/README | 0 extapi/linux/serial.h | 0 extapi/linux/tty_flags.h | 0 extapi/openxcas/libOpenXCASAPI.a | Bin extapi/openxcas/openxcas.conf | 0 extapi/openxcas/openxcas_api.h | 0 extapi/openxcas/openxcas_message.h | 0 extapi/openxcas/openxcas_smartcard.h | 0 globals.h | 0 globals.h.bak | 0 globals.h.orig | 2811 ----- images/image1.jpg | Bin 73977 -> 0 bytes label | 0 minilzo/CMakeLists.txt | 0 minilzo/Makefile | 0 minilzo/README.LZO | 0 minilzo/lzoconf.h | 0 minilzo/lzodefs.h | 0 minilzo/minilzo.c | 0 minilzo/minilzo.h | 0 module-anticasc.c | 0 module-anticasc.h | 0 module-cacheex.c | 0 module-cacheex.c.bak | 0 module-cacheex.h | 0 module-cacheex.h.bak | 0 module-camd33.c | 0 module-camd35-cacheex.c | 0 module-camd35-cacheex.c.orig | 1754 --- module-camd35-cacheex.h | 0 module-camd35.c | 0 module-camd35.h | 0 module-cccam-cacheex.c | 0 module-cccam-cacheex.h | 0 module-cccam-data.h | 0 module-cccam.c | 0 module-cccam.h | 0 module-cccshare.c | 0 module-cccshare.h | 0 module-constcw.c | 0 module-csp.c | 0 module-cw-cycle-check.c | 0 module-cw-cycle-check.h | 0 module-dvbapi-azbox.c | 0 module-dvbapi-azbox.h | 0 module-dvbapi-chancache.c | 0 module-dvbapi-chancache.h | 0 module-dvbapi-coolapi-legacy.c | 0 module-dvbapi-coolapi.c | 0 module-dvbapi-coolapi.h | 0 module-dvbapi-mca.c | 0 module-dvbapi-mca.h | 0 module-dvbapi-stapi.c | 0 module-dvbapi-stapi.h | 0 module-dvbapi-stapi5.c | 0 module-dvbapi.c | 0 module-dvbapi.h | 0 module-emulator-biss.c | 883 -- module-emulator-biss.h | 22 - module-emulator-cryptoworks.c | 688 - module-emulator-cryptoworks.h | 10 - module-emulator-director.c | 644 - module-emulator-director.h | 11 - module-emulator-irdeto.c | 602 - module-emulator-irdeto.h | 15 - module-emulator-nagravision.c | 376 - module-emulator-nagravision.h | 10 - module-emulator-omnicrypt.c | 72 - module-emulator-omnicrypt.h | 10 - module-emulator-osemu.c | 986 -- module-emulator-osemu.h | 96 - module-emulator-powervu.c | 2795 ----- module-emulator-powervu.h | 63 - module-emulator-viaccess.c | 1183 -- module-emulator-viaccess.h | 11 - module-emulator.c | 894 -- module-gbox-cards.c | 0 module-gbox-cards.h | 0 module-gbox-helper.c | 0 module-gbox-helper.h | 0 module-gbox-remm.c | 0 module-gbox-remm.h | 0 module-gbox-sms.c | 0 module-gbox-sms.h | 0 module-gbox.c | 0 module-gbox.h | 0 module-ghttp.c | 0 module-lcd.c | 0 module-lcd.h | 0 module-led.c | 0 module-led.h | 0 module-monitor.c | 0 module-monitor.h | 0 module-newcamd-des.c | 0 module-newcamd-des.h | 0 module-newcamd.c | 0 module-newcamd.h | 0 module-pandora.c | 0 module-radegast.c | 0 module-scam.c | 0 module-serial.c | 0 module-stat.c | 0 module-stat.h | 0 module-streamrelay.c | 0 module-streamrelay.h | 0 module-webif-lib.c | 0 module-webif-lib.h | 0 module-webif-tpl.c | 0 module-webif-tpl.h | 0 module-webif.c | 0 module-webif.c.bak | 0 module-webif.c.orig | 10342 ---------------- module-webif.h | 0 modules.h | 0 oscam-aes.c | 0 oscam-aes.h | 0 oscam-array.c | 0 oscam-array.h | 0 oscam-cache.c | 0 oscam-cache.c.bak | 0 oscam-cache.h | 0 oscam-chk.c | 0 oscam-chk.c.bak | 0 oscam-chk.c.orig | 1316 -- oscam-chk.c.rej | 11 - oscam-chk.h | 0 oscam-client.c | 0 oscam-client.h | 0 oscam-conf-chk.c | 0 oscam-conf-chk.h | 0 oscam-conf-mk.c | 0 oscam-conf-mk.h | 0 oscam-conf.c | 0 oscam-conf.h | 0 oscam-config-account.c | 0 oscam-config-global.c | 0 oscam-config-global.c.bak | 0 oscam-config-reader.c | 0 oscam-config.c | 0 oscam-config.c.orig | 1494 --- oscam-config.h | 0 oscam-ecm.c | 0 oscam-ecm.c.bak | 0 oscam-ecm.c.orig | 3788 ------ oscam-ecm.h | 0 oscam-emm-cache.c | 0 oscam-emm-cache.h | 0 oscam-emm.c | 0 oscam-emm.h | 0 oscam-failban.c | 0 oscam-failban.h | 0 oscam-files.c | 0 oscam-files.h | 0 oscam-garbage.c | 0 oscam-garbage.h | 0 oscam-hashtable.c | 0 oscam-hashtable.h | 0 oscam-llist.c | 0 oscam-llist.h | 0 oscam-lock.c | 0 oscam-lock.h | 0 oscam-log-reader.c | 0 oscam-log-reader.h | 0 oscam-log.c | 0 oscam-log.h | 0 oscam-net.c | 0 oscam-net.h | 0 oscam-reader.c | 0 oscam-reader.h | 0 oscam-signing.c | 0 oscam-signing.h | 0 oscam-simples.c | 0 oscam-string-isotables.h | 0 oscam-string.c | 0 oscam-string.h | 0 oscam-time.c | 0 oscam-time.h | 0 oscam-work.c | 0 oscam-work.h | 0 oscam.c | 0 rcEx | 0 reader-bulcrypt.c | 0 reader-common.c | 0 reader-common.h | 0 reader-conax.c | 0 reader-cryptoworks.c | 0 reader-dgcrypt.c | 0 reader-dre-cas.c | 0 reader-dre-common.c | 0 reader-dre-common.h | 0 reader-dre-st20.c | 0 reader-dre-st20.h | 0 reader-dre.c | 0 reader-griffin.c | 0 reader-irdeto.c | 0 reader-irdeto.h | 0 reader-nagra-common.c | 0 reader-nagra-common.h | 0 reader-nagra.c | 0 reader-nagracak7.c | 0 reader-seca.c | 0 reader-tongfang.c | 0 reader-viaccess.c | 0 reader-videoguard-common.c | 0 reader-videoguard-common.h | 0 reader-videoguard1.c | 0 reader-videoguard12.c | 0 reader-videoguard2.c | 0 readers.h | 0 tests.c | 0 tier | 0 tommyDS_hashlin/tommychain.h | 0 tommyDS_hashlin/tommyhash.c | 0 tommyDS_hashlin/tommyhash.h | 0 tommyDS_hashlin/tommyhashlin.c | 0 tommyDS_hashlin/tommyhashlin.h | 0 tommyDS_hashlin/tommylist.c | 0 tommyDS_hashlin/tommylist.h | 0 tommyDS_hashlin/tommytypes.h | 0 toolchains/toolchain-arm-coolstream.cmake | 0 .../toolchain-arm-dockstar-openwrt.cmake | 0 toolchains/toolchain-arm-friendlyarm.cmake | 0 toolchains/toolchain-arm-mca.cmake | 0 toolchains/toolchain-arm-none.cmake | 0 toolchains/toolchain-arm-nslu2-openwrt.cmake | 0 toolchains/toolchain-arm-nslu2-unslung.cmake | 0 toolchains/toolchain-arm-su980.cmake | 0 .../toolchain-arm-wrt350nv2-openwrt.cmake | 0 toolchains/toolchain-mips-agv2_w.cmake | 0 toolchains/toolchain-mips-azbox.cmake | 0 toolchains/toolchain-mips-dir825.cmake | 0 toolchains/toolchain-mips-fonera2.cmake | 0 toolchains/toolchain-mips-tuxbox.cmake | 0 toolchains/toolchain-mips-wrt54g.cmake | 0 ...olchain-mipsel-tuxbox-broken-pthread.cmake | 0 .../toolchain-mipsel-tuxbox-linux-gnu.cmake | 0 toolchains/toolchain-mipsel-tuxbox.cmake | 0 toolchains/toolchain-powerpc-tuxbox.cmake | 0 toolchains/toolchain-sh4-amino.cmake | 0 toolchains/toolchain-sh4-qboxhd.cmake | 0 toolchains/toolchain-sh4-tuxbox-stapi.cmake | 0 toolchains/toolchain-sh4-tuxbox.cmake | 0 toolchains/toolchain-sparc-padre.cmake | 0 toolchains/toolchain-tripledragon.cmake | 0 utils/CMakeLists.txt | 0 utils/list_smargo.c | 0 webif/.gitignore | 0 webif/Makefile | 0 webif/README | 0 webif/api.json/cacheex.json | 0 webif/api.json/cacheexaiobit.json | 0 webif/api.json/cacheexbit.json | 0 webif/api.json/entitlementbit.json | 0 webif/api.json/entitlements.json | 0 webif/api.json/footer.json | 0 webif/api.json/header.json | 0 webif/api.json/reader.json | 0 webif/api.json/readerbit.json | 0 webif/api.json/status.json | 0 webif/api.json/status_statusbits.json | 0 webif/api.json/user.json | 0 webif/api.json/userbit.json | 0 webif/api.xml/cccamcardlist.xml | 0 webif/api.xml/cccamcardlist_cardlist.xml | 0 .../cccamcardlist_cardlist_nodelist.xml | 0 .../cccamcardlist_cardlist_providerlist.xml | 0 webif/api.xml/confirmation.xml | 0 webif/api.xml/error.xml | 0 webif/api.xml/failban.xml | 0 webif/api.xml/failban_failbanrow.xml | 0 webif/api.xml/file.xml | 0 webif/api.xml/footer.xml | 0 webif/api.xml/header.xml | 0 webif/api.xml/readers.xml | 0 webif/api.xml/readers_readerlist.xml | 0 webif/api.xml/readerstats.xml | 0 webif/api.xml/readerstats_ecmstats.xml | 0 webif/api.xml/readerstats_emmstats.xml | 0 webif/api.xml/status.xml | 0 webif/api.xml/status_statusbits.xml | 0 webif/api.xml/userconfiglist.xml | 0 webif/api.xml/userconfiglist_userconfigs.xml | 0 webif/api.xml/useredit.xml | 0 webif/cacheex/cacheex.html | 0 webif/cacheex/cacheex_tablerow.html | 0 webif/cacheexaio/cacheex.html | 0 webif/cacheexaio/cacheex_tablerow.html | 0 webif/cacheexaio/cacheex_tablerow_stats.html | 0 webif/config/anticasc.html | 0 webif/config/cache.html | 0 webif/config/cache_cacheexaiocsp.html | 0 webif/config/cache_cacheexaiocsp.html.bak | 0 webif/config/cache_cacheexcsp.html | 0 webif/config/cache_cwcycle.html | 0 webif/config/cacheaio.html | 0 webif/config/camd33.html | 0 webif/config/camd35.html | 0 webif/config/camd35tcp.html | 0 webif/config/cccam.html | 0 webif/config/cccam_control.html | 0 webif/config/cccreshare.html | 0 webif/config/config.html | 0 webif/config/dvbapi.html | 0 webif/config/dvbapi_demuxerfix.html | 0 webif/config/dvbapi_extended_cw_api.html | 0 webif/config/gbox.html | 0 webif/config/global.html | 0 webif/config/global.html.bak | 0 webif/config/global_cacheex_aio_logging.html | 0 webif/config/global_enableledbit.html | 0 webif/config/global_getblockemmauprovid.html | 0 webif/config/global_localcards.html | 0 webif/config/global_suppresscmd08.html | 0 webif/config/global_unlockparental.html | 0 webif/config/lcd.html | 0 webif/config/loadbalancer.html | 0 webif/config/loadbalancer_control.html | 0 webif/config/menu.html | 0 webif/config/menu_anticasc.html | 0 webif/config/menu_camd33.html | 0 webif/config/menu_camd35.html | 0 webif/config/menu_camd35tcp.html | 0 webif/config/menu_cccam.html | 0 webif/config/menu_cmcaptioncwc.html | 0 webif/config/menu_dvbapi.html | 0 webif/config/menu_gbox.html | 0 webif/config/menu_lcd.html | 0 webif/config/menu_loadbalancer.html | 0 webif/config/menu_monitor.html | 0 webif/config/menu_newcamd.html | 0 webif/config/menu_radegast.html | 0 webif/config/menu_scam.html | 0 webif/config/menu_serial.html | 0 webif/config/menu_streamrelay.html | 0 webif/config/monitor.html | 0 webif/config/newcamd.html | 0 webif/config/radegast.html | 0 webif/config/scam.html | 0 webif/config/serial.html | 0 webif/config/serial_devices.html | 0 webif/config/streamrelay.html | 0 webif/config/streamrelay_emusettings.html | 9 - webif/config/webif.html | 0 webif/config/webif_httpssl.html | 0 webif/config/webif_show_jquery.html | 0 webif/config/webif_showcacheexinfo.html | 0 webif/emm/emm.html | 0 webif/emm_running/emm_running.html | 0 webif/entitlements/entitlements.html | 0 webif/entitlements/entitlements_bit.html | 0 webif/entitlements/entitlements_bit_nds.html | 0 webif/entitlements/entitlements_cccambit.html | 0 .../entitlements_cccambit_statsentry.html | 0 .../entitlements/entitlements_genericbit.html | 0 webif/entitlements/entitlements_itembit.html | 0 webif/failban/failban.html | 0 webif/failban/failban_failbanrow.html | 0 webif/files/file.html | 0 webif/files/file_edit_css.html | 0 webif/files/file_filterform.html | 0 webif/files/file_writeprotection.html | 0 webif/files/menu.html | 0 webif/files/menu_anticasc.html | 0 webif/files/menu_constantcw.html | 0 webif/files/menu_dvbapi.html | 0 webif/files/menu_fakecws.html | 0 webif/files/menu_gbox.html | 0 webif/files/menu_softcamkey.html | 1 - webif/files/menu_twin.html | 0 webif/ghttp/autoconf.html | 0 webif/ghttp/pre_autoconf.html | 0 webif/graph/graph.svg | 0 webif/images/ICARRL.svg | 0 webif/images/ICARRR.svg | 0 webif/images/ICDEL.svg | 0 webif/images/ICDIS.svg | 0 webif/images/ICEDI.svg | 0 webif/images/ICEMM.svg | 0 webif/images/ICENA.svg | 0 webif/images/ICENT.svg | 0 webif/images/ICHID.svg | 0 webif/images/ICKIL.svg | 0 webif/images/ICMLOGO.svg | 0 webif/images/ICREF.svg | 0 webif/images/ICRES.svg | 0 webif/images/ICSHW.svg | 0 webif/images/ICSPAC.gif | Bin webif/images/ICSTA.svg | 0 webif/images/ICSTART.svg | 0 webif/images/ICSTOP.svg | 0 webif/images/favicon.ico | Bin webif/include/body.html | 0 webif/include/cccamentitlements.html | 0 webif/include/cccamentitletooltip.html | 0 webif/include/css.css | 0 webif/include/footer.html | 0 webif/include/foundentitlements.html | 0 webif/include/header.html | 0 webif/include/header_short.html | 0 webif/include/jquery.js | 0 webif/include/jscript.js | 0 webif/include/logobit.html | 0 webif/include/logobit_img.html | 0 webif/include/menu.html | 0 webif/include/menu_cacheexmenuitem.html | 0 webif/include/message.html | 0 webif/include/message_bit.html | 0 webif/include/noentitlements.html | 0 webif/include/poll.html | 0 webif/include/pollingset.html | 0 webif/include/protocamd3aiopic.html | 0 webif/include/protocccampic.html | 0 webif/include/protonewcamdpic.html | 0 webif/include/protootherpic.html | 0 webif/include/refresh.html | 0 webif/logmenu/log_clearlog.html | 0 webif/logmenu/log_clearuserlog.html | 0 webif/logmenu/log_disablelogmenu.html | 0 webif/logmenu/log_filterform.html | 0 webif/logmenu/log_logmenuonoff.html | 0 webif/logpage/logpage.html | 0 webif/logpage/logpage_debugmenu.html | 0 webif/logpage/logpage_menu.html | 0 webif/logpage/logpage_sizemenu.html | 0 webif/pages_gen.c | 0 webif/pages_index.txt | 0 webif/pages_index_check | 0 webif/pages_mkdep | 0 webif/pages_wiki.c | 754 -- webif/pages_wiki.h | 27 - webif/readerconfig/readerconfig.html | 0 .../readerconfig_cacheexaiobit.html | 0 .../readerconfig/readerconfig_cacheexbit.html | 0 .../readerconfig/readerconfig_camd35bit.html | 0 webif/readerconfig/readerconfig_cccambit.html | 0 .../readerconfig/readerconfig_cs378xbit.html | 0 webif/readerconfig/readerconfig_emubit.html | 2 - webif/readerconfig/readerconfig_gboxbit.html | 0 .../readerconfig_gboxcccresharebit.html | 0 webif/readerconfig/readerconfig_ghttpbit.html | 0 webif/readerconfig/readerconfig_hopbit.html | 0 webif/readerconfig/readerconfig_hwreader.html | 0 .../readerconfig_hwreader_boxkey.html | 0 .../readerconfig_hwreader_conax.html | 0 .../readerconfig_hwreader_cryptoworks.html | 0 .../readerconfig_hwreader_deskey.html | 0 .../readerconfig_hwreader_dre.html | 0 .../readerconfig_hwreader_irdeto.html | 0 .../readerconfig_hwreader_nagra.html | 0 .../readerconfig_hwreader_nagracak7.html | 0 .../readerconfig_hwreader_nano.html | 0 .../readerconfig_hwreader_pincode.html | 0 .../readerconfig_hwreader_rsakey.html | 0 .../readerconfig_hwreader_sc8in1.html | 0 .../readerconfig_hwreader_smargo.html | 0 .../readerconfig_hwreader_tongfang.html | 0 .../readerconfig_hwreader_viaccess.html | 0 .../readerconfig_hwreader_videoguard.html | 0 webif/readerconfig/readerconfig_ipv6bit.html | 0 webif/readerconfig/readerconfig_lbweight.html | 0 .../readerconfig/readerconfig_ncd524bit.html | 0 .../readerconfig/readerconfig_ncd525bit.html | 0 .../readerconfig_radegastbit.html | 0 webif/readerconfig/readerconfig_scambit.html | 0 webif/readerconfig/readerconfig_sid.html | 0 .../readerconfig/readerconfig_sidlbokbit.html | 0 webif/readerconfig/readerconfig_sidnobit.html | 0 webif/readerconfig/readerconfig_sidokbit.html | 0 webif/readerconfig/readerconfigaio.html | 0 webif/readerconfig/readerinfo_gbox_remm.html | 0 webif/readers/readerctypbit.html | 0 webif/readers/readerctypnoicon.html | 0 webif/readers/readerlabel.html | 0 webif/readers/readernamebit.html | 0 webif/readers/readernoicon.html | 0 webif/readers/readers.html | 0 webif/readers/readers_lblweightbit.html | 0 webif/readers/readers_lblweightd.html | 0 webif/readers/readers_lblweightu.html | 0 webif/readers/readers_readerlist.html | 0 .../readers_readerlist_entitlement.html | 0 webif/readers/readers_readerlist_lbstat.html | 0 webif/readers/readers_readerlist_refresh.html | 0 .../readers/readers_readerlist_writeemm.html | 0 webif/readers/readersaio.html | 0 webif/readers/readersaio_readerlist.html | 0 webif/readerstats/readerstats.html | 0 webif/readerstats/readerstats_nostats.html | 0 webif/readerstats/readerstats_statsbit.html | 0 webif/readerstats/readerstatsinvalid.html | 0 webif/readerstats/readerstatsnotfound.html | 0 webif/readerstats/readerstatsrowbit.html | 0 webif/readerstats/readerstatstimeoutbit.html | 0 webif/savetemplates/savetemplates.html | 0 webif/scanusb/scanusb.html | 0 webif/scanusb/scanusb_pcscbit.html | 0 webif/scanusb/scanusb_udevbit.html | 0 webif/scanusb/scanusb_usbbit.html | 0 webif/script/script.html | 0 webif/services/services.html | 0 webif/services/services_servicetabs.html | 0 .../services_servicetabs_sidlist.html | 0 webif/services_edit/services_edit.html | 0 webif/services_edit/services_editaio.html | 0 webif/shutdown/pre_shutdown.html | 0 webif/shutdown/shutdown.html | 0 webif/status/status.html | 0 webif/status/status_cacheexaioinfo.html | 0 webif/status/status_cacheexinfo.html | 0 webif/status/status_cheadline.html | 0 webif/status/status_cheadlineadd.html | 0 webif/status/status_clientheadlinebit.html | 0 webif/status/status_clientstatusbit.html | 0 webif/status/status_currentchannel.html | 0 webif/status/status_currentchannelbit.html | 0 webif/status/status_currentchannelpic.html | 0 webif/status/status_headline.html | 0 webif/status/status_hidebutton.html | 0 webif/status/status_killbutton.html | 0 webif/status/status_lblvaluereaderbit.html | 0 webif/status/status_lbvaluereaderproxy.html | 0 webif/status/status_loghistory.html | 0 webif/status/status_mheadline.html | 0 webif/status/status_pheadline.html | 0 webif/status/status_pheadlineadd.html | 0 webif/status/status_reader.html | 0 webif/status/status_readericon.html | 0 webif/status/status_readerinfo.html | 0 webif/status/status_restartbutton.html | 0 webif/status/status_rheadline.html | 0 webif/status/status_rheadlineadd.html | 0 webif/status/status_sdebug.html | 0 webif/status/status_sdebugaio.html | 0 webif/status/status_sheadline.html | 0 webif/status/status_systeminfo.html | 0 webif/status/status_user.html | 0 webif/status/status_usericon.html | 0 webif/status/status_userinfo.html | 0 webif/user_edit/user_edit.html | 0 webif/user_edit/user_edit_anticasc.html | 0 webif/user_edit/user_edit_cacheexaiobit.html | 0 webif/user_edit/user_edit_cacheexbit.html | 0 webif/user_edit/user_edit_cccam.html | 0 webif/user_edit/user_edit_cwcycle.html | 0 webif/user_edit/user_edit_monlevel.html | 0 webif/user_edit/user_edit_sid.html | 0 webif/user_edit/user_edit_sidnobit.html | 0 webif/user_edit/user_edit_sidokbit.html | 0 webif/user_edit/user_editaio.html | 0 webif/userconfig/userconfig.html | 0 webif/userconfig/userconfig_anticascbit.html | 0 .../userconfig/userconfig_cwanticascthv.html | 0 webif/userconfig/userconfig_cwcyclebit.html | 0 webif/userconfig/userconfig_cwcyclethv.html | 0 webif/userconfig/userconfig_entry.html | 0 .../userconfig_entry_cwanticasctbv.html | 0 .../userconfig_entry_cwcycletbv.html | 0 .../userconfig_lastchannelicon.html | 0 webif/userconfig/userconfig_newuserform.html | 0 webif/userconfig/userconfig_notify.html | 0 webif/userconfig/userconfig_usericon.html | 0 webif/userconfig/userconfig_userlabel.html | 0 webif/userconfig/userconfig_usernoicon.html | 0 webif/wiki/wiki.json | 0 webif/wiki/wikierror.json | 0 webif/wiki/wikinotfound.json | 0 webif/wiki/wikistatus.json | 0 webif/wiki_gen | Bin 35256 -> 0 bytes webif/wiki_gen.c | 0 wiki | 1 - 736 files changed, 31681 deletions(-) mode change 100644 => 100755 .gitignore mode change 100644 => 100755 .gitmodules mode change 100644 => 100755 CMakeLists.txt mode change 100644 => 100755 CODING.RULES.txt mode change 100644 => 100755 COPYING mode change 100644 => 100755 Distribution/doc/example/oscam.ac mode change 100644 => 100755 Distribution/doc/example/oscam.cacheex mode change 100644 => 100755 Distribution/doc/example/oscam.cert mode change 100644 => 100755 Distribution/doc/example/oscam.conf mode change 100644 => 100755 Distribution/doc/example/oscam.dvbapi mode change 100644 => 100755 Distribution/doc/example/oscam.guess mode change 100644 => 100755 Distribution/doc/example/oscam.ird mode change 100644 => 100755 Distribution/doc/example/oscam.provid mode change 100644 => 100755 Distribution/doc/example/oscam.server mode change 100644 => 100755 Distribution/doc/example/oscam.services mode change 100644 => 100755 Distribution/doc/example/oscam.srvid mode change 100644 => 100755 Distribution/doc/example/oscam.tiers mode change 100644 => 100755 Distribution/doc/example/oscam.user mode change 100644 => 100755 Distribution/doc/example/oscam.whitelist mode change 100644 => 100755 Distribution/doc/html/list_smargo.1.html mode change 100644 => 100755 Distribution/doc/html/oscam.1.html mode change 100644 => 100755 Distribution/doc/html/oscam.ac.5.html mode change 100644 => 100755 Distribution/doc/html/oscam.cacheex.5.html mode change 100644 => 100755 Distribution/doc/html/oscam.cert.5.html mode change 100644 => 100755 Distribution/doc/html/oscam.conf.5.html mode change 100644 => 100755 Distribution/doc/html/oscam.dvbapi.5.html mode change 100644 => 100755 Distribution/doc/html/oscam.guess.5.html mode change 100644 => 100755 Distribution/doc/html/oscam.ird.5.html mode change 100644 => 100755 Distribution/doc/html/oscam.provid.5.html mode change 100644 => 100755 Distribution/doc/html/oscam.ratelimit.5.html mode change 100644 => 100755 Distribution/doc/html/oscam.server.5.html mode change 100644 => 100755 Distribution/doc/html/oscam.services.5.html mode change 100644 => 100755 Distribution/doc/html/oscam.srvid.5.html mode change 100644 => 100755 Distribution/doc/html/oscam.srvid2.5.html mode change 100644 => 100755 Distribution/doc/html/oscam.tiers.5.html mode change 100644 => 100755 Distribution/doc/html/oscam.user.5.html mode change 100644 => 100755 Distribution/doc/html/oscam.whitelist.5.html mode change 100644 => 100755 Distribution/doc/man/list_smargo.1 mode change 100644 => 100755 Distribution/doc/man/oscam.1 mode change 100644 => 100755 Distribution/doc/man/oscam.ac.5 mode change 100644 => 100755 Distribution/doc/man/oscam.cacheex.5 mode change 100644 => 100755 Distribution/doc/man/oscam.cert.5 mode change 100644 => 100755 Distribution/doc/man/oscam.conf.5 mode change 100644 => 100755 Distribution/doc/man/oscam.dvbapi.5 mode change 100644 => 100755 Distribution/doc/man/oscam.guess.5 mode change 100644 => 100755 Distribution/doc/man/oscam.ird.5 mode change 100644 => 100755 Distribution/doc/man/oscam.provid.5 mode change 100644 => 100755 Distribution/doc/man/oscam.ratelimit.5 mode change 100644 => 100755 Distribution/doc/man/oscam.server.5 mode change 100644 => 100755 Distribution/doc/man/oscam.services.5 mode change 100644 => 100755 Distribution/doc/man/oscam.srvid.5 mode change 100644 => 100755 Distribution/doc/man/oscam.srvid2.5 mode change 100644 => 100755 Distribution/doc/man/oscam.tiers.5 mode change 100644 => 100755 Distribution/doc/man/oscam.user.5 mode change 100644 => 100755 Distribution/doc/man/oscam.whitelist.5 mode change 100644 => 100755 Distribution/doc/txt/list_smargo.txt mode change 100644 => 100755 Distribution/doc/txt/oscam.ac.txt mode change 100644 => 100755 Distribution/doc/txt/oscam.cacheex.txt mode change 100644 => 100755 Distribution/doc/txt/oscam.cert.txt mode change 100644 => 100755 Distribution/doc/txt/oscam.conf.txt mode change 100644 => 100755 Distribution/doc/txt/oscam.dvbapi.txt mode change 100644 => 100755 Distribution/doc/txt/oscam.guess.txt mode change 100644 => 100755 Distribution/doc/txt/oscam.ird.txt mode change 100644 => 100755 Distribution/doc/txt/oscam.provid.txt mode change 100644 => 100755 Distribution/doc/txt/oscam.ratelimit.txt mode change 100644 => 100755 Distribution/doc/txt/oscam.server.txt mode change 100644 => 100755 Distribution/doc/txt/oscam.services.txt mode change 100644 => 100755 Distribution/doc/txt/oscam.srvid.txt mode change 100644 => 100755 Distribution/doc/txt/oscam.srvid2.txt mode change 100644 => 100755 Distribution/doc/txt/oscam.tiers.txt mode change 100644 => 100755 Distribution/doc/txt/oscam.txt mode change 100644 => 100755 Distribution/doc/txt/oscam.user.txt mode change 100644 => 100755 Distribution/doc/txt/oscam.whitelist.txt mode change 100644 => 100755 Distribution/monitor/mpcsmon-src-0.6.tar.bz2 mode change 100644 => 100755 Distribution/monitor/mpcsmon.sh mode change 100644 => 100755 Makefile mode change 100644 => 100755 Makefile.extra mode change 100644 => 100755 README.build mode change 100644 => 100755 README.config mode change 100644 => 100755 README.dvbapi_protocol mode change 100644 => 100755 README.md delete mode 100755 SoftCam.Key mode change 100644 => 100755 caid, mode change 100644 => 100755 config.h mode change 100644 => 100755 config.mak mode change 100644 => 100755 config.sh mode change 100644 => 100755 cscrypt/CMakeLists.txt mode change 100644 => 100755 cscrypt/Makefile mode change 100644 => 100755 cscrypt/aes.c mode change 100644 => 100755 cscrypt/aes.h mode change 100644 => 100755 cscrypt/bn.h mode change 100644 => 100755 cscrypt/bn_add.c mode change 100644 => 100755 cscrypt/bn_asm.c mode change 100644 => 100755 cscrypt/bn_ctx.c mode change 100644 => 100755 cscrypt/bn_div.c mode change 100644 => 100755 cscrypt/bn_exp.c mode change 100644 => 100755 cscrypt/bn_lcl.h mode change 100644 => 100755 cscrypt/bn_lib.c mode change 100644 => 100755 cscrypt/bn_mul.c mode change 100644 => 100755 cscrypt/bn_print.c mode change 100644 => 100755 cscrypt/bn_shift.c mode change 100644 => 100755 cscrypt/bn_sqr.c mode change 100644 => 100755 cscrypt/bn_word.c mode change 100644 => 100755 cscrypt/buffer.h mode change 100644 => 100755 cscrypt/des.c mode change 100644 => 100755 cscrypt/des.h mode change 100644 => 100755 cscrypt/fast_aes.c mode change 100644 => 100755 cscrypt/fast_aes.h mode change 100644 => 100755 cscrypt/i_cbc.c mode change 100644 => 100755 cscrypt/i_ecb.c mode change 100644 => 100755 cscrypt/i_skey.c mode change 100644 => 100755 cscrypt/idea.h mode change 100644 => 100755 cscrypt/idea_lcl.h mode change 100644 => 100755 cscrypt/md5.c mode change 100644 => 100755 cscrypt/md5.h mode change 100644 => 100755 cscrypt/mdc2.c mode change 100644 => 100755 cscrypt/mdc2.h mode change 100644 => 100755 cscrypt/mem.c mode change 100644 => 100755 cscrypt/openssl_mods.h mode change 100644 => 100755 cscrypt/rc6.c mode change 100644 => 100755 cscrypt/rc6.h mode change 100644 => 100755 cscrypt/sha1.c mode change 100644 => 100755 cscrypt/sha1.h mode change 100644 => 100755 cscrypt/sha256.c mode change 100644 => 100755 cscrypt/sha256.h mode change 100644 => 100755 csctapi/CMakeLists.txt mode change 100644 => 100755 csctapi/Makefile mode change 100644 => 100755 csctapi/atr.c mode change 100644 => 100755 csctapi/atr.h mode change 100644 => 100755 csctapi/cardreaders.h mode change 100644 => 100755 csctapi/icc_async.c mode change 100644 => 100755 csctapi/icc_async.h mode change 100644 => 100755 csctapi/ifd_amsmc.c mode change 100644 => 100755 csctapi/ifd_azbox.c mode change 100644 => 100755 csctapi/ifd_cool.c mode change 100644 => 100755 csctapi/ifd_db2com.c mode change 100644 => 100755 csctapi/ifd_db2com.h mode change 100644 => 100755 csctapi/ifd_drecas.c mode change 100644 => 100755 csctapi/ifd_drecas.h mode change 100644 => 100755 csctapi/ifd_mp35.c mode change 100644 => 100755 csctapi/ifd_pcsc.c mode change 100644 => 100755 csctapi/ifd_phoenix.c mode change 100644 => 100755 csctapi/ifd_phoenix.h mode change 100644 => 100755 csctapi/ifd_sc8in1.c mode change 100644 => 100755 csctapi/ifd_sci.c mode change 100644 => 100755 csctapi/ifd_sci_global.h mode change 100644 => 100755 csctapi/ifd_sci_ioctl.h mode change 100644 => 100755 csctapi/ifd_smargo.c mode change 100644 => 100755 csctapi/ifd_smartreader.c mode change 100644 => 100755 csctapi/ifd_smartreader_types.h mode change 100644 => 100755 csctapi/ifd_stapi.c mode change 100644 => 100755 csctapi/ifd_stinger.c mode change 100644 => 100755 csctapi/io_serial.c mode change 100644 => 100755 csctapi/io_serial.h mode change 100644 => 100755 csctapi/protocol_t0.c mode change 100644 => 100755 csctapi/protocol_t0.h mode change 100644 => 100755 csctapi/protocol_t1.c mode change 100644 => 100755 devtools/README mode change 100644 => 100755 devtools/check_cmdline_opts.sh mode change 100644 => 100755 devtools/check_config_tables.sh mode change 100644 => 100755 devtools/extract_config.sh mode change 100644 => 100755 extapi/README mode change 100644 => 100755 extapi/coolapi.h mode change 100644 => 100755 extapi/cygwin/SCardErr.h mode change 100644 => 100755 extapi/cygwin/WinSCard.h mode change 100644 => 100755 extapi/cygwin/WinSmCrd.h mode change 100644 => 100755 extapi/linux/README mode change 100644 => 100755 extapi/linux/serial.h mode change 100644 => 100755 extapi/linux/tty_flags.h mode change 100644 => 100755 extapi/openxcas/libOpenXCASAPI.a mode change 100644 => 100755 extapi/openxcas/openxcas.conf mode change 100644 => 100755 extapi/openxcas/openxcas_api.h mode change 100644 => 100755 extapi/openxcas/openxcas_message.h mode change 100644 => 100755 extapi/openxcas/openxcas_smartcard.h mode change 100644 => 100755 globals.h mode change 100644 => 100755 globals.h.bak delete mode 100755 globals.h.orig delete mode 100755 images/image1.jpg mode change 100644 => 100755 label mode change 100644 => 100755 minilzo/CMakeLists.txt mode change 100644 => 100755 minilzo/Makefile mode change 100644 => 100755 minilzo/README.LZO mode change 100644 => 100755 minilzo/lzoconf.h mode change 100644 => 100755 minilzo/lzodefs.h mode change 100644 => 100755 minilzo/minilzo.c mode change 100644 => 100755 minilzo/minilzo.h mode change 100644 => 100755 module-anticasc.c mode change 100644 => 100755 module-anticasc.h mode change 100644 => 100755 module-cacheex.c mode change 100644 => 100755 module-cacheex.c.bak mode change 100644 => 100755 module-cacheex.h mode change 100644 => 100755 module-cacheex.h.bak mode change 100644 => 100755 module-camd33.c mode change 100644 => 100755 module-camd35-cacheex.c delete mode 100755 module-camd35-cacheex.c.orig mode change 100644 => 100755 module-camd35-cacheex.h mode change 100644 => 100755 module-camd35.c mode change 100644 => 100755 module-camd35.h mode change 100644 => 100755 module-cccam-cacheex.c mode change 100644 => 100755 module-cccam-cacheex.h mode change 100644 => 100755 module-cccam-data.h mode change 100644 => 100755 module-cccam.c mode change 100644 => 100755 module-cccam.h mode change 100644 => 100755 module-cccshare.c mode change 100644 => 100755 module-cccshare.h mode change 100644 => 100755 module-constcw.c mode change 100644 => 100755 module-csp.c mode change 100644 => 100755 module-cw-cycle-check.c mode change 100644 => 100755 module-cw-cycle-check.h mode change 100644 => 100755 module-dvbapi-azbox.c mode change 100644 => 100755 module-dvbapi-azbox.h mode change 100644 => 100755 module-dvbapi-chancache.c mode change 100644 => 100755 module-dvbapi-chancache.h mode change 100644 => 100755 module-dvbapi-coolapi-legacy.c mode change 100644 => 100755 module-dvbapi-coolapi.c mode change 100644 => 100755 module-dvbapi-coolapi.h mode change 100644 => 100755 module-dvbapi-mca.c mode change 100644 => 100755 module-dvbapi-mca.h mode change 100644 => 100755 module-dvbapi-stapi.c mode change 100644 => 100755 module-dvbapi-stapi.h mode change 100644 => 100755 module-dvbapi-stapi5.c mode change 100644 => 100755 module-dvbapi.c mode change 100644 => 100755 module-dvbapi.h delete mode 100755 module-emulator-biss.c delete mode 100755 module-emulator-biss.h delete mode 100755 module-emulator-cryptoworks.c delete mode 100755 module-emulator-cryptoworks.h delete mode 100755 module-emulator-director.c delete mode 100755 module-emulator-director.h delete mode 100755 module-emulator-irdeto.c delete mode 100755 module-emulator-irdeto.h delete mode 100755 module-emulator-nagravision.c delete mode 100755 module-emulator-nagravision.h delete mode 100755 module-emulator-omnicrypt.c delete mode 100755 module-emulator-omnicrypt.h delete mode 100755 module-emulator-osemu.c delete mode 100755 module-emulator-osemu.h delete mode 100755 module-emulator-powervu.c delete mode 100755 module-emulator-powervu.h delete mode 100755 module-emulator-viaccess.c delete mode 100755 module-emulator-viaccess.h delete mode 100755 module-emulator.c mode change 100644 => 100755 module-gbox-cards.c mode change 100644 => 100755 module-gbox-cards.h mode change 100644 => 100755 module-gbox-helper.c mode change 100644 => 100755 module-gbox-helper.h mode change 100644 => 100755 module-gbox-remm.c mode change 100644 => 100755 module-gbox-remm.h mode change 100644 => 100755 module-gbox-sms.c mode change 100644 => 100755 module-gbox-sms.h mode change 100644 => 100755 module-gbox.c mode change 100644 => 100755 module-gbox.h mode change 100644 => 100755 module-ghttp.c mode change 100644 => 100755 module-lcd.c mode change 100644 => 100755 module-lcd.h mode change 100644 => 100755 module-led.c mode change 100644 => 100755 module-led.h mode change 100644 => 100755 module-monitor.c mode change 100644 => 100755 module-monitor.h mode change 100644 => 100755 module-newcamd-des.c mode change 100644 => 100755 module-newcamd-des.h mode change 100644 => 100755 module-newcamd.c mode change 100644 => 100755 module-newcamd.h mode change 100644 => 100755 module-pandora.c mode change 100644 => 100755 module-radegast.c mode change 100644 => 100755 module-scam.c mode change 100644 => 100755 module-serial.c mode change 100644 => 100755 module-stat.c mode change 100644 => 100755 module-stat.h mode change 100644 => 100755 module-streamrelay.c mode change 100644 => 100755 module-streamrelay.h mode change 100644 => 100755 module-webif-lib.c mode change 100644 => 100755 module-webif-lib.h mode change 100644 => 100755 module-webif-tpl.c mode change 100644 => 100755 module-webif-tpl.h mode change 100644 => 100755 module-webif.c mode change 100644 => 100755 module-webif.c.bak delete mode 100755 module-webif.c.orig mode change 100644 => 100755 module-webif.h mode change 100644 => 100755 modules.h mode change 100644 => 100755 oscam-aes.c mode change 100644 => 100755 oscam-aes.h mode change 100644 => 100755 oscam-array.c mode change 100644 => 100755 oscam-array.h mode change 100644 => 100755 oscam-cache.c mode change 100644 => 100755 oscam-cache.c.bak mode change 100644 => 100755 oscam-cache.h mode change 100644 => 100755 oscam-chk.c mode change 100644 => 100755 oscam-chk.c.bak delete mode 100755 oscam-chk.c.orig delete mode 100755 oscam-chk.c.rej mode change 100644 => 100755 oscam-chk.h mode change 100644 => 100755 oscam-client.c mode change 100644 => 100755 oscam-client.h mode change 100644 => 100755 oscam-conf-chk.c mode change 100644 => 100755 oscam-conf-chk.h mode change 100644 => 100755 oscam-conf-mk.c mode change 100644 => 100755 oscam-conf-mk.h mode change 100644 => 100755 oscam-conf.c mode change 100644 => 100755 oscam-conf.h mode change 100644 => 100755 oscam-config-account.c mode change 100644 => 100755 oscam-config-global.c mode change 100644 => 100755 oscam-config-global.c.bak mode change 100644 => 100755 oscam-config-reader.c mode change 100644 => 100755 oscam-config.c delete mode 100755 oscam-config.c.orig mode change 100644 => 100755 oscam-config.h mode change 100644 => 100755 oscam-ecm.c mode change 100644 => 100755 oscam-ecm.c.bak delete mode 100755 oscam-ecm.c.orig mode change 100644 => 100755 oscam-ecm.h mode change 100644 => 100755 oscam-emm-cache.c mode change 100644 => 100755 oscam-emm-cache.h mode change 100644 => 100755 oscam-emm.c mode change 100644 => 100755 oscam-emm.h mode change 100644 => 100755 oscam-failban.c mode change 100644 => 100755 oscam-failban.h mode change 100644 => 100755 oscam-files.c mode change 100644 => 100755 oscam-files.h mode change 100644 => 100755 oscam-garbage.c mode change 100644 => 100755 oscam-garbage.h mode change 100644 => 100755 oscam-hashtable.c mode change 100644 => 100755 oscam-hashtable.h mode change 100644 => 100755 oscam-llist.c mode change 100644 => 100755 oscam-llist.h mode change 100644 => 100755 oscam-lock.c mode change 100644 => 100755 oscam-lock.h mode change 100644 => 100755 oscam-log-reader.c mode change 100644 => 100755 oscam-log-reader.h mode change 100644 => 100755 oscam-log.c mode change 100644 => 100755 oscam-log.h mode change 100644 => 100755 oscam-net.c mode change 100644 => 100755 oscam-net.h mode change 100644 => 100755 oscam-reader.c mode change 100644 => 100755 oscam-reader.h mode change 100644 => 100755 oscam-signing.c mode change 100644 => 100755 oscam-signing.h mode change 100644 => 100755 oscam-simples.c mode change 100644 => 100755 oscam-string-isotables.h mode change 100644 => 100755 oscam-string.c mode change 100644 => 100755 oscam-string.h mode change 100644 => 100755 oscam-time.c mode change 100644 => 100755 oscam-time.h mode change 100644 => 100755 oscam-work.c mode change 100644 => 100755 oscam-work.h mode change 100644 => 100755 oscam.c mode change 100644 => 100755 rcEx mode change 100644 => 100755 reader-bulcrypt.c mode change 100644 => 100755 reader-common.c mode change 100644 => 100755 reader-common.h mode change 100644 => 100755 reader-conax.c mode change 100644 => 100755 reader-cryptoworks.c mode change 100644 => 100755 reader-dgcrypt.c mode change 100644 => 100755 reader-dre-cas.c mode change 100644 => 100755 reader-dre-common.c mode change 100644 => 100755 reader-dre-common.h mode change 100644 => 100755 reader-dre-st20.c mode change 100644 => 100755 reader-dre-st20.h mode change 100644 => 100755 reader-dre.c mode change 100644 => 100755 reader-griffin.c mode change 100644 => 100755 reader-irdeto.c mode change 100644 => 100755 reader-irdeto.h mode change 100644 => 100755 reader-nagra-common.c mode change 100644 => 100755 reader-nagra-common.h mode change 100644 => 100755 reader-nagra.c mode change 100644 => 100755 reader-nagracak7.c mode change 100644 => 100755 reader-seca.c mode change 100644 => 100755 reader-tongfang.c mode change 100644 => 100755 reader-viaccess.c mode change 100644 => 100755 reader-videoguard-common.c mode change 100644 => 100755 reader-videoguard-common.h mode change 100644 => 100755 reader-videoguard1.c mode change 100644 => 100755 reader-videoguard12.c mode change 100644 => 100755 reader-videoguard2.c mode change 100644 => 100755 readers.h mode change 100644 => 100755 tests.c mode change 100644 => 100755 tier mode change 100644 => 100755 tommyDS_hashlin/tommychain.h mode change 100644 => 100755 tommyDS_hashlin/tommyhash.c mode change 100644 => 100755 tommyDS_hashlin/tommyhash.h mode change 100644 => 100755 tommyDS_hashlin/tommyhashlin.c mode change 100644 => 100755 tommyDS_hashlin/tommyhashlin.h mode change 100644 => 100755 tommyDS_hashlin/tommylist.c mode change 100644 => 100755 tommyDS_hashlin/tommylist.h mode change 100644 => 100755 tommyDS_hashlin/tommytypes.h mode change 100644 => 100755 toolchains/toolchain-arm-coolstream.cmake mode change 100644 => 100755 toolchains/toolchain-arm-dockstar-openwrt.cmake mode change 100644 => 100755 toolchains/toolchain-arm-friendlyarm.cmake mode change 100644 => 100755 toolchains/toolchain-arm-mca.cmake mode change 100644 => 100755 toolchains/toolchain-arm-none.cmake mode change 100644 => 100755 toolchains/toolchain-arm-nslu2-openwrt.cmake mode change 100644 => 100755 toolchains/toolchain-arm-nslu2-unslung.cmake mode change 100644 => 100755 toolchains/toolchain-arm-su980.cmake mode change 100644 => 100755 toolchains/toolchain-arm-wrt350nv2-openwrt.cmake mode change 100644 => 100755 toolchains/toolchain-mips-agv2_w.cmake mode change 100644 => 100755 toolchains/toolchain-mips-azbox.cmake mode change 100644 => 100755 toolchains/toolchain-mips-dir825.cmake mode change 100644 => 100755 toolchains/toolchain-mips-fonera2.cmake mode change 100644 => 100755 toolchains/toolchain-mips-tuxbox.cmake mode change 100644 => 100755 toolchains/toolchain-mips-wrt54g.cmake mode change 100644 => 100755 toolchains/toolchain-mipsel-tuxbox-broken-pthread.cmake mode change 100644 => 100755 toolchains/toolchain-mipsel-tuxbox-linux-gnu.cmake mode change 100644 => 100755 toolchains/toolchain-mipsel-tuxbox.cmake mode change 100644 => 100755 toolchains/toolchain-powerpc-tuxbox.cmake mode change 100644 => 100755 toolchains/toolchain-sh4-amino.cmake mode change 100644 => 100755 toolchains/toolchain-sh4-qboxhd.cmake mode change 100644 => 100755 toolchains/toolchain-sh4-tuxbox-stapi.cmake mode change 100644 => 100755 toolchains/toolchain-sh4-tuxbox.cmake mode change 100644 => 100755 toolchains/toolchain-sparc-padre.cmake mode change 100644 => 100755 toolchains/toolchain-tripledragon.cmake mode change 100644 => 100755 utils/CMakeLists.txt mode change 100644 => 100755 utils/list_smargo.c mode change 100644 => 100755 webif/.gitignore mode change 100644 => 100755 webif/Makefile mode change 100644 => 100755 webif/README mode change 100644 => 100755 webif/api.json/cacheex.json mode change 100644 => 100755 webif/api.json/cacheexaiobit.json mode change 100644 => 100755 webif/api.json/cacheexbit.json mode change 100644 => 100755 webif/api.json/entitlementbit.json mode change 100644 => 100755 webif/api.json/entitlements.json mode change 100644 => 100755 webif/api.json/footer.json mode change 100644 => 100755 webif/api.json/header.json mode change 100644 => 100755 webif/api.json/reader.json mode change 100644 => 100755 webif/api.json/readerbit.json mode change 100644 => 100755 webif/api.json/status.json mode change 100644 => 100755 webif/api.json/status_statusbits.json mode change 100644 => 100755 webif/api.json/user.json mode change 100644 => 100755 webif/api.json/userbit.json mode change 100644 => 100755 webif/api.xml/cccamcardlist.xml mode change 100644 => 100755 webif/api.xml/cccamcardlist_cardlist.xml mode change 100644 => 100755 webif/api.xml/cccamcardlist_cardlist_nodelist.xml mode change 100644 => 100755 webif/api.xml/cccamcardlist_cardlist_providerlist.xml mode change 100644 => 100755 webif/api.xml/confirmation.xml mode change 100644 => 100755 webif/api.xml/error.xml mode change 100644 => 100755 webif/api.xml/failban.xml mode change 100644 => 100755 webif/api.xml/failban_failbanrow.xml mode change 100644 => 100755 webif/api.xml/file.xml mode change 100644 => 100755 webif/api.xml/footer.xml mode change 100644 => 100755 webif/api.xml/header.xml mode change 100644 => 100755 webif/api.xml/readers.xml mode change 100644 => 100755 webif/api.xml/readers_readerlist.xml mode change 100644 => 100755 webif/api.xml/readerstats.xml mode change 100644 => 100755 webif/api.xml/readerstats_ecmstats.xml mode change 100644 => 100755 webif/api.xml/readerstats_emmstats.xml mode change 100644 => 100755 webif/api.xml/status.xml mode change 100644 => 100755 webif/api.xml/status_statusbits.xml mode change 100644 => 100755 webif/api.xml/userconfiglist.xml mode change 100644 => 100755 webif/api.xml/userconfiglist_userconfigs.xml mode change 100644 => 100755 webif/api.xml/useredit.xml mode change 100644 => 100755 webif/cacheex/cacheex.html mode change 100644 => 100755 webif/cacheex/cacheex_tablerow.html mode change 100644 => 100755 webif/cacheexaio/cacheex.html mode change 100644 => 100755 webif/cacheexaio/cacheex_tablerow.html mode change 100644 => 100755 webif/cacheexaio/cacheex_tablerow_stats.html mode change 100644 => 100755 webif/config/anticasc.html mode change 100644 => 100755 webif/config/cache.html mode change 100644 => 100755 webif/config/cache_cacheexaiocsp.html mode change 100644 => 100755 webif/config/cache_cacheexaiocsp.html.bak mode change 100644 => 100755 webif/config/cache_cacheexcsp.html mode change 100644 => 100755 webif/config/cache_cwcycle.html mode change 100644 => 100755 webif/config/cacheaio.html mode change 100644 => 100755 webif/config/camd33.html mode change 100644 => 100755 webif/config/camd35.html mode change 100644 => 100755 webif/config/camd35tcp.html mode change 100644 => 100755 webif/config/cccam.html mode change 100644 => 100755 webif/config/cccam_control.html mode change 100644 => 100755 webif/config/cccreshare.html mode change 100644 => 100755 webif/config/config.html mode change 100644 => 100755 webif/config/dvbapi.html mode change 100644 => 100755 webif/config/dvbapi_demuxerfix.html mode change 100644 => 100755 webif/config/dvbapi_extended_cw_api.html mode change 100644 => 100755 webif/config/gbox.html mode change 100644 => 100755 webif/config/global.html mode change 100644 => 100755 webif/config/global.html.bak mode change 100644 => 100755 webif/config/global_cacheex_aio_logging.html mode change 100644 => 100755 webif/config/global_enableledbit.html mode change 100644 => 100755 webif/config/global_getblockemmauprovid.html mode change 100644 => 100755 webif/config/global_localcards.html mode change 100644 => 100755 webif/config/global_suppresscmd08.html mode change 100644 => 100755 webif/config/global_unlockparental.html mode change 100644 => 100755 webif/config/lcd.html mode change 100644 => 100755 webif/config/loadbalancer.html mode change 100644 => 100755 webif/config/loadbalancer_control.html mode change 100644 => 100755 webif/config/menu.html mode change 100644 => 100755 webif/config/menu_anticasc.html mode change 100644 => 100755 webif/config/menu_camd33.html mode change 100644 => 100755 webif/config/menu_camd35.html mode change 100644 => 100755 webif/config/menu_camd35tcp.html mode change 100644 => 100755 webif/config/menu_cccam.html mode change 100644 => 100755 webif/config/menu_cmcaptioncwc.html mode change 100644 => 100755 webif/config/menu_dvbapi.html mode change 100644 => 100755 webif/config/menu_gbox.html mode change 100644 => 100755 webif/config/menu_lcd.html mode change 100644 => 100755 webif/config/menu_loadbalancer.html mode change 100644 => 100755 webif/config/menu_monitor.html mode change 100644 => 100755 webif/config/menu_newcamd.html mode change 100644 => 100755 webif/config/menu_radegast.html mode change 100644 => 100755 webif/config/menu_scam.html mode change 100644 => 100755 webif/config/menu_serial.html mode change 100644 => 100755 webif/config/menu_streamrelay.html mode change 100644 => 100755 webif/config/monitor.html mode change 100644 => 100755 webif/config/newcamd.html mode change 100644 => 100755 webif/config/radegast.html mode change 100644 => 100755 webif/config/scam.html mode change 100644 => 100755 webif/config/serial.html mode change 100644 => 100755 webif/config/serial_devices.html mode change 100644 => 100755 webif/config/streamrelay.html delete mode 100755 webif/config/streamrelay_emusettings.html mode change 100644 => 100755 webif/config/webif.html mode change 100644 => 100755 webif/config/webif_httpssl.html mode change 100644 => 100755 webif/config/webif_show_jquery.html mode change 100644 => 100755 webif/config/webif_showcacheexinfo.html mode change 100644 => 100755 webif/emm/emm.html mode change 100644 => 100755 webif/emm_running/emm_running.html mode change 100644 => 100755 webif/entitlements/entitlements.html mode change 100644 => 100755 webif/entitlements/entitlements_bit.html mode change 100644 => 100755 webif/entitlements/entitlements_bit_nds.html mode change 100644 => 100755 webif/entitlements/entitlements_cccambit.html mode change 100644 => 100755 webif/entitlements/entitlements_cccambit_statsentry.html mode change 100644 => 100755 webif/entitlements/entitlements_genericbit.html mode change 100644 => 100755 webif/entitlements/entitlements_itembit.html mode change 100644 => 100755 webif/failban/failban.html mode change 100644 => 100755 webif/failban/failban_failbanrow.html mode change 100644 => 100755 webif/files/file.html mode change 100644 => 100755 webif/files/file_edit_css.html mode change 100644 => 100755 webif/files/file_filterform.html mode change 100644 => 100755 webif/files/file_writeprotection.html mode change 100644 => 100755 webif/files/menu.html mode change 100644 => 100755 webif/files/menu_anticasc.html mode change 100644 => 100755 webif/files/menu_constantcw.html mode change 100644 => 100755 webif/files/menu_dvbapi.html mode change 100644 => 100755 webif/files/menu_fakecws.html mode change 100644 => 100755 webif/files/menu_gbox.html delete mode 100755 webif/files/menu_softcamkey.html mode change 100644 => 100755 webif/files/menu_twin.html mode change 100644 => 100755 webif/ghttp/autoconf.html mode change 100644 => 100755 webif/ghttp/pre_autoconf.html mode change 100644 => 100755 webif/graph/graph.svg mode change 100644 => 100755 webif/images/ICARRL.svg mode change 100644 => 100755 webif/images/ICARRR.svg mode change 100644 => 100755 webif/images/ICDEL.svg mode change 100644 => 100755 webif/images/ICDIS.svg mode change 100644 => 100755 webif/images/ICEDI.svg mode change 100644 => 100755 webif/images/ICEMM.svg mode change 100644 => 100755 webif/images/ICENA.svg mode change 100644 => 100755 webif/images/ICENT.svg mode change 100644 => 100755 webif/images/ICHID.svg mode change 100644 => 100755 webif/images/ICKIL.svg mode change 100644 => 100755 webif/images/ICMLOGO.svg mode change 100644 => 100755 webif/images/ICREF.svg mode change 100644 => 100755 webif/images/ICRES.svg mode change 100644 => 100755 webif/images/ICSHW.svg mode change 100644 => 100755 webif/images/ICSPAC.gif mode change 100644 => 100755 webif/images/ICSTA.svg mode change 100644 => 100755 webif/images/ICSTART.svg mode change 100644 => 100755 webif/images/ICSTOP.svg mode change 100644 => 100755 webif/images/favicon.ico mode change 100644 => 100755 webif/include/body.html mode change 100644 => 100755 webif/include/cccamentitlements.html mode change 100644 => 100755 webif/include/cccamentitletooltip.html mode change 100644 => 100755 webif/include/css.css mode change 100644 => 100755 webif/include/footer.html mode change 100644 => 100755 webif/include/foundentitlements.html mode change 100644 => 100755 webif/include/header.html mode change 100644 => 100755 webif/include/header_short.html mode change 100644 => 100755 webif/include/jquery.js mode change 100644 => 100755 webif/include/jscript.js mode change 100644 => 100755 webif/include/logobit.html mode change 100644 => 100755 webif/include/logobit_img.html mode change 100644 => 100755 webif/include/menu.html mode change 100644 => 100755 webif/include/menu_cacheexmenuitem.html mode change 100644 => 100755 webif/include/message.html mode change 100644 => 100755 webif/include/message_bit.html mode change 100644 => 100755 webif/include/noentitlements.html mode change 100644 => 100755 webif/include/poll.html mode change 100644 => 100755 webif/include/pollingset.html mode change 100644 => 100755 webif/include/protocamd3aiopic.html mode change 100644 => 100755 webif/include/protocccampic.html mode change 100644 => 100755 webif/include/protonewcamdpic.html mode change 100644 => 100755 webif/include/protootherpic.html mode change 100644 => 100755 webif/include/refresh.html mode change 100644 => 100755 webif/logmenu/log_clearlog.html mode change 100644 => 100755 webif/logmenu/log_clearuserlog.html mode change 100644 => 100755 webif/logmenu/log_disablelogmenu.html mode change 100644 => 100755 webif/logmenu/log_filterform.html mode change 100644 => 100755 webif/logmenu/log_logmenuonoff.html mode change 100644 => 100755 webif/logpage/logpage.html mode change 100644 => 100755 webif/logpage/logpage_debugmenu.html mode change 100644 => 100755 webif/logpage/logpage_menu.html mode change 100644 => 100755 webif/logpage/logpage_sizemenu.html mode change 100644 => 100755 webif/pages_gen.c mode change 100644 => 100755 webif/pages_index.txt mode change 100644 => 100755 webif/pages_index_check mode change 100644 => 100755 webif/pages_mkdep delete mode 100644 webif/pages_wiki.c delete mode 100644 webif/pages_wiki.h mode change 100644 => 100755 webif/readerconfig/readerconfig.html mode change 100644 => 100755 webif/readerconfig/readerconfig_cacheexaiobit.html mode change 100644 => 100755 webif/readerconfig/readerconfig_cacheexbit.html mode change 100644 => 100755 webif/readerconfig/readerconfig_camd35bit.html mode change 100644 => 100755 webif/readerconfig/readerconfig_cccambit.html mode change 100644 => 100755 webif/readerconfig/readerconfig_cs378xbit.html delete mode 100755 webif/readerconfig/readerconfig_emubit.html mode change 100644 => 100755 webif/readerconfig/readerconfig_gboxbit.html mode change 100644 => 100755 webif/readerconfig/readerconfig_gboxcccresharebit.html mode change 100644 => 100755 webif/readerconfig/readerconfig_ghttpbit.html mode change 100644 => 100755 webif/readerconfig/readerconfig_hopbit.html mode change 100644 => 100755 webif/readerconfig/readerconfig_hwreader.html mode change 100644 => 100755 webif/readerconfig/readerconfig_hwreader_boxkey.html mode change 100644 => 100755 webif/readerconfig/readerconfig_hwreader_conax.html mode change 100644 => 100755 webif/readerconfig/readerconfig_hwreader_cryptoworks.html mode change 100644 => 100755 webif/readerconfig/readerconfig_hwreader_deskey.html mode change 100644 => 100755 webif/readerconfig/readerconfig_hwreader_dre.html mode change 100644 => 100755 webif/readerconfig/readerconfig_hwreader_irdeto.html mode change 100644 => 100755 webif/readerconfig/readerconfig_hwreader_nagra.html mode change 100644 => 100755 webif/readerconfig/readerconfig_hwreader_nagracak7.html mode change 100644 => 100755 webif/readerconfig/readerconfig_hwreader_nano.html mode change 100644 => 100755 webif/readerconfig/readerconfig_hwreader_pincode.html mode change 100644 => 100755 webif/readerconfig/readerconfig_hwreader_rsakey.html mode change 100644 => 100755 webif/readerconfig/readerconfig_hwreader_sc8in1.html mode change 100644 => 100755 webif/readerconfig/readerconfig_hwreader_smargo.html mode change 100644 => 100755 webif/readerconfig/readerconfig_hwreader_tongfang.html mode change 100644 => 100755 webif/readerconfig/readerconfig_hwreader_viaccess.html mode change 100644 => 100755 webif/readerconfig/readerconfig_hwreader_videoguard.html mode change 100644 => 100755 webif/readerconfig/readerconfig_ipv6bit.html mode change 100644 => 100755 webif/readerconfig/readerconfig_lbweight.html mode change 100644 => 100755 webif/readerconfig/readerconfig_ncd524bit.html mode change 100644 => 100755 webif/readerconfig/readerconfig_ncd525bit.html mode change 100644 => 100755 webif/readerconfig/readerconfig_radegastbit.html mode change 100644 => 100755 webif/readerconfig/readerconfig_scambit.html mode change 100644 => 100755 webif/readerconfig/readerconfig_sid.html mode change 100644 => 100755 webif/readerconfig/readerconfig_sidlbokbit.html mode change 100644 => 100755 webif/readerconfig/readerconfig_sidnobit.html mode change 100644 => 100755 webif/readerconfig/readerconfig_sidokbit.html mode change 100644 => 100755 webif/readerconfig/readerconfigaio.html mode change 100644 => 100755 webif/readerconfig/readerinfo_gbox_remm.html mode change 100644 => 100755 webif/readers/readerctypbit.html mode change 100644 => 100755 webif/readers/readerctypnoicon.html mode change 100644 => 100755 webif/readers/readerlabel.html mode change 100644 => 100755 webif/readers/readernamebit.html mode change 100644 => 100755 webif/readers/readernoicon.html mode change 100644 => 100755 webif/readers/readers.html mode change 100644 => 100755 webif/readers/readers_lblweightbit.html mode change 100644 => 100755 webif/readers/readers_lblweightd.html mode change 100644 => 100755 webif/readers/readers_lblweightu.html mode change 100644 => 100755 webif/readers/readers_readerlist.html mode change 100644 => 100755 webif/readers/readers_readerlist_entitlement.html mode change 100644 => 100755 webif/readers/readers_readerlist_lbstat.html mode change 100644 => 100755 webif/readers/readers_readerlist_refresh.html mode change 100644 => 100755 webif/readers/readers_readerlist_writeemm.html mode change 100644 => 100755 webif/readers/readersaio.html mode change 100644 => 100755 webif/readers/readersaio_readerlist.html mode change 100644 => 100755 webif/readerstats/readerstats.html mode change 100644 => 100755 webif/readerstats/readerstats_nostats.html mode change 100644 => 100755 webif/readerstats/readerstats_statsbit.html mode change 100644 => 100755 webif/readerstats/readerstatsinvalid.html mode change 100644 => 100755 webif/readerstats/readerstatsnotfound.html mode change 100644 => 100755 webif/readerstats/readerstatsrowbit.html mode change 100644 => 100755 webif/readerstats/readerstatstimeoutbit.html mode change 100644 => 100755 webif/savetemplates/savetemplates.html mode change 100644 => 100755 webif/scanusb/scanusb.html mode change 100644 => 100755 webif/scanusb/scanusb_pcscbit.html mode change 100644 => 100755 webif/scanusb/scanusb_udevbit.html mode change 100644 => 100755 webif/scanusb/scanusb_usbbit.html mode change 100644 => 100755 webif/script/script.html mode change 100644 => 100755 webif/services/services.html mode change 100644 => 100755 webif/services/services_servicetabs.html mode change 100644 => 100755 webif/services/services_servicetabs_sidlist.html mode change 100644 => 100755 webif/services_edit/services_edit.html mode change 100644 => 100755 webif/services_edit/services_editaio.html mode change 100644 => 100755 webif/shutdown/pre_shutdown.html mode change 100644 => 100755 webif/shutdown/shutdown.html mode change 100644 => 100755 webif/status/status.html mode change 100644 => 100755 webif/status/status_cacheexaioinfo.html mode change 100644 => 100755 webif/status/status_cacheexinfo.html mode change 100644 => 100755 webif/status/status_cheadline.html mode change 100644 => 100755 webif/status/status_cheadlineadd.html mode change 100644 => 100755 webif/status/status_clientheadlinebit.html mode change 100644 => 100755 webif/status/status_clientstatusbit.html mode change 100644 => 100755 webif/status/status_currentchannel.html mode change 100644 => 100755 webif/status/status_currentchannelbit.html mode change 100644 => 100755 webif/status/status_currentchannelpic.html mode change 100644 => 100755 webif/status/status_headline.html mode change 100644 => 100755 webif/status/status_hidebutton.html mode change 100644 => 100755 webif/status/status_killbutton.html mode change 100644 => 100755 webif/status/status_lblvaluereaderbit.html mode change 100644 => 100755 webif/status/status_lbvaluereaderproxy.html mode change 100644 => 100755 webif/status/status_loghistory.html mode change 100644 => 100755 webif/status/status_mheadline.html mode change 100644 => 100755 webif/status/status_pheadline.html mode change 100644 => 100755 webif/status/status_pheadlineadd.html mode change 100644 => 100755 webif/status/status_reader.html mode change 100644 => 100755 webif/status/status_readericon.html mode change 100644 => 100755 webif/status/status_readerinfo.html mode change 100644 => 100755 webif/status/status_restartbutton.html mode change 100644 => 100755 webif/status/status_rheadline.html mode change 100644 => 100755 webif/status/status_rheadlineadd.html mode change 100644 => 100755 webif/status/status_sdebug.html mode change 100644 => 100755 webif/status/status_sdebugaio.html mode change 100644 => 100755 webif/status/status_sheadline.html mode change 100644 => 100755 webif/status/status_systeminfo.html mode change 100644 => 100755 webif/status/status_user.html mode change 100644 => 100755 webif/status/status_usericon.html mode change 100644 => 100755 webif/status/status_userinfo.html mode change 100644 => 100755 webif/user_edit/user_edit.html mode change 100644 => 100755 webif/user_edit/user_edit_anticasc.html mode change 100644 => 100755 webif/user_edit/user_edit_cacheexaiobit.html mode change 100644 => 100755 webif/user_edit/user_edit_cacheexbit.html mode change 100644 => 100755 webif/user_edit/user_edit_cccam.html mode change 100644 => 100755 webif/user_edit/user_edit_cwcycle.html mode change 100644 => 100755 webif/user_edit/user_edit_monlevel.html mode change 100644 => 100755 webif/user_edit/user_edit_sid.html mode change 100644 => 100755 webif/user_edit/user_edit_sidnobit.html mode change 100644 => 100755 webif/user_edit/user_edit_sidokbit.html mode change 100644 => 100755 webif/user_edit/user_editaio.html mode change 100644 => 100755 webif/userconfig/userconfig.html mode change 100644 => 100755 webif/userconfig/userconfig_anticascbit.html mode change 100644 => 100755 webif/userconfig/userconfig_cwanticascthv.html mode change 100644 => 100755 webif/userconfig/userconfig_cwcyclebit.html mode change 100644 => 100755 webif/userconfig/userconfig_cwcyclethv.html mode change 100644 => 100755 webif/userconfig/userconfig_entry.html mode change 100644 => 100755 webif/userconfig/userconfig_entry_cwanticasctbv.html mode change 100644 => 100755 webif/userconfig/userconfig_entry_cwcycletbv.html mode change 100644 => 100755 webif/userconfig/userconfig_lastchannelicon.html mode change 100644 => 100755 webif/userconfig/userconfig_newuserform.html mode change 100644 => 100755 webif/userconfig/userconfig_notify.html mode change 100644 => 100755 webif/userconfig/userconfig_usericon.html mode change 100644 => 100755 webif/userconfig/userconfig_userlabel.html mode change 100644 => 100755 webif/userconfig/userconfig_usernoicon.html mode change 100644 => 100755 webif/wiki/wiki.json mode change 100644 => 100755 webif/wiki/wikierror.json mode change 100644 => 100755 webif/wiki/wikinotfound.json mode change 100644 => 100755 webif/wiki/wikistatus.json delete mode 100755 webif/wiki_gen mode change 100644 => 100755 webif/wiki_gen.c delete mode 160000 wiki diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/.gitmodules b/.gitmodules old mode 100644 new mode 100755 diff --git a/CMakeLists.txt b/CMakeLists.txt old mode 100644 new mode 100755 diff --git a/CODING.RULES.txt b/CODING.RULES.txt old mode 100644 new mode 100755 diff --git a/COPYING b/COPYING old mode 100644 new mode 100755 diff --git a/Distribution/doc/example/oscam.ac b/Distribution/doc/example/oscam.ac old mode 100644 new mode 100755 diff --git a/Distribution/doc/example/oscam.cacheex b/Distribution/doc/example/oscam.cacheex old mode 100644 new mode 100755 diff --git a/Distribution/doc/example/oscam.cert b/Distribution/doc/example/oscam.cert old mode 100644 new mode 100755 diff --git a/Distribution/doc/example/oscam.conf b/Distribution/doc/example/oscam.conf old mode 100644 new mode 100755 diff --git a/Distribution/doc/example/oscam.dvbapi b/Distribution/doc/example/oscam.dvbapi old mode 100644 new mode 100755 diff --git a/Distribution/doc/example/oscam.guess b/Distribution/doc/example/oscam.guess old mode 100644 new mode 100755 diff --git a/Distribution/doc/example/oscam.ird b/Distribution/doc/example/oscam.ird old mode 100644 new mode 100755 diff --git a/Distribution/doc/example/oscam.provid b/Distribution/doc/example/oscam.provid old mode 100644 new mode 100755 diff --git a/Distribution/doc/example/oscam.server b/Distribution/doc/example/oscam.server old mode 100644 new mode 100755 diff --git a/Distribution/doc/example/oscam.services b/Distribution/doc/example/oscam.services old mode 100644 new mode 100755 diff --git a/Distribution/doc/example/oscam.srvid b/Distribution/doc/example/oscam.srvid old mode 100644 new mode 100755 diff --git a/Distribution/doc/example/oscam.tiers b/Distribution/doc/example/oscam.tiers old mode 100644 new mode 100755 diff --git a/Distribution/doc/example/oscam.user b/Distribution/doc/example/oscam.user old mode 100644 new mode 100755 diff --git a/Distribution/doc/example/oscam.whitelist b/Distribution/doc/example/oscam.whitelist old mode 100644 new mode 100755 diff --git a/Distribution/doc/html/list_smargo.1.html b/Distribution/doc/html/list_smargo.1.html old mode 100644 new mode 100755 diff --git a/Distribution/doc/html/oscam.1.html b/Distribution/doc/html/oscam.1.html old mode 100644 new mode 100755 diff --git a/Distribution/doc/html/oscam.ac.5.html b/Distribution/doc/html/oscam.ac.5.html old mode 100644 new mode 100755 diff --git a/Distribution/doc/html/oscam.cacheex.5.html b/Distribution/doc/html/oscam.cacheex.5.html old mode 100644 new mode 100755 diff --git a/Distribution/doc/html/oscam.cert.5.html b/Distribution/doc/html/oscam.cert.5.html old mode 100644 new mode 100755 diff --git a/Distribution/doc/html/oscam.conf.5.html b/Distribution/doc/html/oscam.conf.5.html old mode 100644 new mode 100755 diff --git a/Distribution/doc/html/oscam.dvbapi.5.html b/Distribution/doc/html/oscam.dvbapi.5.html old mode 100644 new mode 100755 diff --git a/Distribution/doc/html/oscam.guess.5.html b/Distribution/doc/html/oscam.guess.5.html old mode 100644 new mode 100755 diff --git a/Distribution/doc/html/oscam.ird.5.html b/Distribution/doc/html/oscam.ird.5.html old mode 100644 new mode 100755 diff --git a/Distribution/doc/html/oscam.provid.5.html b/Distribution/doc/html/oscam.provid.5.html old mode 100644 new mode 100755 diff --git a/Distribution/doc/html/oscam.ratelimit.5.html b/Distribution/doc/html/oscam.ratelimit.5.html old mode 100644 new mode 100755 diff --git a/Distribution/doc/html/oscam.server.5.html b/Distribution/doc/html/oscam.server.5.html old mode 100644 new mode 100755 diff --git a/Distribution/doc/html/oscam.services.5.html b/Distribution/doc/html/oscam.services.5.html old mode 100644 new mode 100755 diff --git a/Distribution/doc/html/oscam.srvid.5.html b/Distribution/doc/html/oscam.srvid.5.html old mode 100644 new mode 100755 diff --git a/Distribution/doc/html/oscam.srvid2.5.html b/Distribution/doc/html/oscam.srvid2.5.html old mode 100644 new mode 100755 diff --git a/Distribution/doc/html/oscam.tiers.5.html b/Distribution/doc/html/oscam.tiers.5.html old mode 100644 new mode 100755 diff --git a/Distribution/doc/html/oscam.user.5.html b/Distribution/doc/html/oscam.user.5.html old mode 100644 new mode 100755 diff --git a/Distribution/doc/html/oscam.whitelist.5.html b/Distribution/doc/html/oscam.whitelist.5.html old mode 100644 new mode 100755 diff --git a/Distribution/doc/man/list_smargo.1 b/Distribution/doc/man/list_smargo.1 old mode 100644 new mode 100755 diff --git a/Distribution/doc/man/oscam.1 b/Distribution/doc/man/oscam.1 old mode 100644 new mode 100755 diff --git a/Distribution/doc/man/oscam.ac.5 b/Distribution/doc/man/oscam.ac.5 old mode 100644 new mode 100755 diff --git a/Distribution/doc/man/oscam.cacheex.5 b/Distribution/doc/man/oscam.cacheex.5 old mode 100644 new mode 100755 diff --git a/Distribution/doc/man/oscam.cert.5 b/Distribution/doc/man/oscam.cert.5 old mode 100644 new mode 100755 diff --git a/Distribution/doc/man/oscam.conf.5 b/Distribution/doc/man/oscam.conf.5 old mode 100644 new mode 100755 diff --git a/Distribution/doc/man/oscam.dvbapi.5 b/Distribution/doc/man/oscam.dvbapi.5 old mode 100644 new mode 100755 diff --git a/Distribution/doc/man/oscam.guess.5 b/Distribution/doc/man/oscam.guess.5 old mode 100644 new mode 100755 diff --git a/Distribution/doc/man/oscam.ird.5 b/Distribution/doc/man/oscam.ird.5 old mode 100644 new mode 100755 diff --git a/Distribution/doc/man/oscam.provid.5 b/Distribution/doc/man/oscam.provid.5 old mode 100644 new mode 100755 diff --git a/Distribution/doc/man/oscam.ratelimit.5 b/Distribution/doc/man/oscam.ratelimit.5 old mode 100644 new mode 100755 diff --git a/Distribution/doc/man/oscam.server.5 b/Distribution/doc/man/oscam.server.5 old mode 100644 new mode 100755 diff --git a/Distribution/doc/man/oscam.services.5 b/Distribution/doc/man/oscam.services.5 old mode 100644 new mode 100755 diff --git a/Distribution/doc/man/oscam.srvid.5 b/Distribution/doc/man/oscam.srvid.5 old mode 100644 new mode 100755 diff --git a/Distribution/doc/man/oscam.srvid2.5 b/Distribution/doc/man/oscam.srvid2.5 old mode 100644 new mode 100755 diff --git a/Distribution/doc/man/oscam.tiers.5 b/Distribution/doc/man/oscam.tiers.5 old mode 100644 new mode 100755 diff --git a/Distribution/doc/man/oscam.user.5 b/Distribution/doc/man/oscam.user.5 old mode 100644 new mode 100755 diff --git a/Distribution/doc/man/oscam.whitelist.5 b/Distribution/doc/man/oscam.whitelist.5 old mode 100644 new mode 100755 diff --git a/Distribution/doc/txt/list_smargo.txt b/Distribution/doc/txt/list_smargo.txt old mode 100644 new mode 100755 diff --git a/Distribution/doc/txt/oscam.ac.txt b/Distribution/doc/txt/oscam.ac.txt old mode 100644 new mode 100755 diff --git a/Distribution/doc/txt/oscam.cacheex.txt b/Distribution/doc/txt/oscam.cacheex.txt old mode 100644 new mode 100755 diff --git a/Distribution/doc/txt/oscam.cert.txt b/Distribution/doc/txt/oscam.cert.txt old mode 100644 new mode 100755 diff --git a/Distribution/doc/txt/oscam.conf.txt b/Distribution/doc/txt/oscam.conf.txt old mode 100644 new mode 100755 diff --git a/Distribution/doc/txt/oscam.dvbapi.txt b/Distribution/doc/txt/oscam.dvbapi.txt old mode 100644 new mode 100755 diff --git a/Distribution/doc/txt/oscam.guess.txt b/Distribution/doc/txt/oscam.guess.txt old mode 100644 new mode 100755 diff --git a/Distribution/doc/txt/oscam.ird.txt b/Distribution/doc/txt/oscam.ird.txt old mode 100644 new mode 100755 diff --git a/Distribution/doc/txt/oscam.provid.txt b/Distribution/doc/txt/oscam.provid.txt old mode 100644 new mode 100755 diff --git a/Distribution/doc/txt/oscam.ratelimit.txt b/Distribution/doc/txt/oscam.ratelimit.txt old mode 100644 new mode 100755 diff --git a/Distribution/doc/txt/oscam.server.txt b/Distribution/doc/txt/oscam.server.txt old mode 100644 new mode 100755 diff --git a/Distribution/doc/txt/oscam.services.txt b/Distribution/doc/txt/oscam.services.txt old mode 100644 new mode 100755 diff --git a/Distribution/doc/txt/oscam.srvid.txt b/Distribution/doc/txt/oscam.srvid.txt old mode 100644 new mode 100755 diff --git a/Distribution/doc/txt/oscam.srvid2.txt b/Distribution/doc/txt/oscam.srvid2.txt old mode 100644 new mode 100755 diff --git a/Distribution/doc/txt/oscam.tiers.txt b/Distribution/doc/txt/oscam.tiers.txt old mode 100644 new mode 100755 diff --git a/Distribution/doc/txt/oscam.txt b/Distribution/doc/txt/oscam.txt old mode 100644 new mode 100755 diff --git a/Distribution/doc/txt/oscam.user.txt b/Distribution/doc/txt/oscam.user.txt old mode 100644 new mode 100755 diff --git a/Distribution/doc/txt/oscam.whitelist.txt b/Distribution/doc/txt/oscam.whitelist.txt old mode 100644 new mode 100755 diff --git a/Distribution/monitor/mpcsmon-src-0.6.tar.bz2 b/Distribution/monitor/mpcsmon-src-0.6.tar.bz2 old mode 100644 new mode 100755 diff --git a/Distribution/monitor/mpcsmon.sh b/Distribution/monitor/mpcsmon.sh old mode 100644 new mode 100755 diff --git a/Makefile b/Makefile old mode 100644 new mode 100755 diff --git a/Makefile.extra b/Makefile.extra old mode 100644 new mode 100755 diff --git a/README.build b/README.build old mode 100644 new mode 100755 diff --git a/README.config b/README.config old mode 100644 new mode 100755 diff --git a/README.dvbapi_protocol b/README.dvbapi_protocol old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/SoftCam.Key b/SoftCam.Key deleted file mode 100755 index e69de29..0000000 diff --git a/caid, b/caid, old mode 100644 new mode 100755 diff --git a/config.h b/config.h old mode 100644 new mode 100755 diff --git a/config.mak b/config.mak old mode 100644 new mode 100755 diff --git a/config.sh b/config.sh old mode 100644 new mode 100755 diff --git a/cscrypt/CMakeLists.txt b/cscrypt/CMakeLists.txt old mode 100644 new mode 100755 diff --git a/cscrypt/Makefile b/cscrypt/Makefile old mode 100644 new mode 100755 diff --git a/cscrypt/aes.c b/cscrypt/aes.c old mode 100644 new mode 100755 diff --git a/cscrypt/aes.h b/cscrypt/aes.h old mode 100644 new mode 100755 diff --git a/cscrypt/bn.h b/cscrypt/bn.h old mode 100644 new mode 100755 diff --git a/cscrypt/bn_add.c b/cscrypt/bn_add.c old mode 100644 new mode 100755 diff --git a/cscrypt/bn_asm.c b/cscrypt/bn_asm.c old mode 100644 new mode 100755 diff --git a/cscrypt/bn_ctx.c b/cscrypt/bn_ctx.c old mode 100644 new mode 100755 diff --git a/cscrypt/bn_div.c b/cscrypt/bn_div.c old mode 100644 new mode 100755 diff --git a/cscrypt/bn_exp.c b/cscrypt/bn_exp.c old mode 100644 new mode 100755 diff --git a/cscrypt/bn_lcl.h b/cscrypt/bn_lcl.h old mode 100644 new mode 100755 diff --git a/cscrypt/bn_lib.c b/cscrypt/bn_lib.c old mode 100644 new mode 100755 diff --git a/cscrypt/bn_mul.c b/cscrypt/bn_mul.c old mode 100644 new mode 100755 diff --git a/cscrypt/bn_print.c b/cscrypt/bn_print.c old mode 100644 new mode 100755 diff --git a/cscrypt/bn_shift.c b/cscrypt/bn_shift.c old mode 100644 new mode 100755 diff --git a/cscrypt/bn_sqr.c b/cscrypt/bn_sqr.c old mode 100644 new mode 100755 diff --git a/cscrypt/bn_word.c b/cscrypt/bn_word.c old mode 100644 new mode 100755 diff --git a/cscrypt/buffer.h b/cscrypt/buffer.h old mode 100644 new mode 100755 diff --git a/cscrypt/des.c b/cscrypt/des.c old mode 100644 new mode 100755 diff --git a/cscrypt/des.h b/cscrypt/des.h old mode 100644 new mode 100755 diff --git a/cscrypt/fast_aes.c b/cscrypt/fast_aes.c old mode 100644 new mode 100755 diff --git a/cscrypt/fast_aes.h b/cscrypt/fast_aes.h old mode 100644 new mode 100755 diff --git a/cscrypt/i_cbc.c b/cscrypt/i_cbc.c old mode 100644 new mode 100755 diff --git a/cscrypt/i_ecb.c b/cscrypt/i_ecb.c old mode 100644 new mode 100755 diff --git a/cscrypt/i_skey.c b/cscrypt/i_skey.c old mode 100644 new mode 100755 diff --git a/cscrypt/idea.h b/cscrypt/idea.h old mode 100644 new mode 100755 diff --git a/cscrypt/idea_lcl.h b/cscrypt/idea_lcl.h old mode 100644 new mode 100755 diff --git a/cscrypt/md5.c b/cscrypt/md5.c old mode 100644 new mode 100755 diff --git a/cscrypt/md5.h b/cscrypt/md5.h old mode 100644 new mode 100755 diff --git a/cscrypt/mdc2.c b/cscrypt/mdc2.c old mode 100644 new mode 100755 diff --git a/cscrypt/mdc2.h b/cscrypt/mdc2.h old mode 100644 new mode 100755 diff --git a/cscrypt/mem.c b/cscrypt/mem.c old mode 100644 new mode 100755 diff --git a/cscrypt/openssl_mods.h b/cscrypt/openssl_mods.h old mode 100644 new mode 100755 diff --git a/cscrypt/rc6.c b/cscrypt/rc6.c old mode 100644 new mode 100755 diff --git a/cscrypt/rc6.h b/cscrypt/rc6.h old mode 100644 new mode 100755 diff --git a/cscrypt/sha1.c b/cscrypt/sha1.c old mode 100644 new mode 100755 diff --git a/cscrypt/sha1.h b/cscrypt/sha1.h old mode 100644 new mode 100755 diff --git a/cscrypt/sha256.c b/cscrypt/sha256.c old mode 100644 new mode 100755 diff --git a/cscrypt/sha256.h b/cscrypt/sha256.h old mode 100644 new mode 100755 diff --git a/csctapi/CMakeLists.txt b/csctapi/CMakeLists.txt old mode 100644 new mode 100755 diff --git a/csctapi/Makefile b/csctapi/Makefile old mode 100644 new mode 100755 diff --git a/csctapi/atr.c b/csctapi/atr.c old mode 100644 new mode 100755 diff --git a/csctapi/atr.h b/csctapi/atr.h old mode 100644 new mode 100755 diff --git a/csctapi/cardreaders.h b/csctapi/cardreaders.h old mode 100644 new mode 100755 diff --git a/csctapi/icc_async.c b/csctapi/icc_async.c old mode 100644 new mode 100755 diff --git a/csctapi/icc_async.h b/csctapi/icc_async.h old mode 100644 new mode 100755 diff --git a/csctapi/ifd_amsmc.c b/csctapi/ifd_amsmc.c old mode 100644 new mode 100755 diff --git a/csctapi/ifd_azbox.c b/csctapi/ifd_azbox.c old mode 100644 new mode 100755 diff --git a/csctapi/ifd_cool.c b/csctapi/ifd_cool.c old mode 100644 new mode 100755 diff --git a/csctapi/ifd_db2com.c b/csctapi/ifd_db2com.c old mode 100644 new mode 100755 diff --git a/csctapi/ifd_db2com.h b/csctapi/ifd_db2com.h old mode 100644 new mode 100755 diff --git a/csctapi/ifd_drecas.c b/csctapi/ifd_drecas.c old mode 100644 new mode 100755 diff --git a/csctapi/ifd_drecas.h b/csctapi/ifd_drecas.h old mode 100644 new mode 100755 diff --git a/csctapi/ifd_mp35.c b/csctapi/ifd_mp35.c old mode 100644 new mode 100755 diff --git a/csctapi/ifd_pcsc.c b/csctapi/ifd_pcsc.c old mode 100644 new mode 100755 diff --git a/csctapi/ifd_phoenix.c b/csctapi/ifd_phoenix.c old mode 100644 new mode 100755 diff --git a/csctapi/ifd_phoenix.h b/csctapi/ifd_phoenix.h old mode 100644 new mode 100755 diff --git a/csctapi/ifd_sc8in1.c b/csctapi/ifd_sc8in1.c old mode 100644 new mode 100755 diff --git a/csctapi/ifd_sci.c b/csctapi/ifd_sci.c old mode 100644 new mode 100755 diff --git a/csctapi/ifd_sci_global.h b/csctapi/ifd_sci_global.h old mode 100644 new mode 100755 diff --git a/csctapi/ifd_sci_ioctl.h b/csctapi/ifd_sci_ioctl.h old mode 100644 new mode 100755 diff --git a/csctapi/ifd_smargo.c b/csctapi/ifd_smargo.c old mode 100644 new mode 100755 diff --git a/csctapi/ifd_smartreader.c b/csctapi/ifd_smartreader.c old mode 100644 new mode 100755 diff --git a/csctapi/ifd_smartreader_types.h b/csctapi/ifd_smartreader_types.h old mode 100644 new mode 100755 diff --git a/csctapi/ifd_stapi.c b/csctapi/ifd_stapi.c old mode 100644 new mode 100755 diff --git a/csctapi/ifd_stinger.c b/csctapi/ifd_stinger.c old mode 100644 new mode 100755 diff --git a/csctapi/io_serial.c b/csctapi/io_serial.c old mode 100644 new mode 100755 diff --git a/csctapi/io_serial.h b/csctapi/io_serial.h old mode 100644 new mode 100755 diff --git a/csctapi/protocol_t0.c b/csctapi/protocol_t0.c old mode 100644 new mode 100755 diff --git a/csctapi/protocol_t0.h b/csctapi/protocol_t0.h old mode 100644 new mode 100755 diff --git a/csctapi/protocol_t1.c b/csctapi/protocol_t1.c old mode 100644 new mode 100755 diff --git a/devtools/README b/devtools/README old mode 100644 new mode 100755 diff --git a/devtools/check_cmdline_opts.sh b/devtools/check_cmdline_opts.sh old mode 100644 new mode 100755 diff --git a/devtools/check_config_tables.sh b/devtools/check_config_tables.sh old mode 100644 new mode 100755 diff --git a/devtools/extract_config.sh b/devtools/extract_config.sh old mode 100644 new mode 100755 diff --git a/extapi/README b/extapi/README old mode 100644 new mode 100755 diff --git a/extapi/coolapi.h b/extapi/coolapi.h old mode 100644 new mode 100755 diff --git a/extapi/cygwin/SCardErr.h b/extapi/cygwin/SCardErr.h old mode 100644 new mode 100755 diff --git a/extapi/cygwin/WinSCard.h b/extapi/cygwin/WinSCard.h old mode 100644 new mode 100755 diff --git a/extapi/cygwin/WinSmCrd.h b/extapi/cygwin/WinSmCrd.h old mode 100644 new mode 100755 diff --git a/extapi/linux/README b/extapi/linux/README old mode 100644 new mode 100755 diff --git a/extapi/linux/serial.h b/extapi/linux/serial.h old mode 100644 new mode 100755 diff --git a/extapi/linux/tty_flags.h b/extapi/linux/tty_flags.h old mode 100644 new mode 100755 diff --git a/extapi/openxcas/libOpenXCASAPI.a b/extapi/openxcas/libOpenXCASAPI.a old mode 100644 new mode 100755 diff --git a/extapi/openxcas/openxcas.conf b/extapi/openxcas/openxcas.conf old mode 100644 new mode 100755 diff --git a/extapi/openxcas/openxcas_api.h b/extapi/openxcas/openxcas_api.h old mode 100644 new mode 100755 diff --git a/extapi/openxcas/openxcas_message.h b/extapi/openxcas/openxcas_message.h old mode 100644 new mode 100755 diff --git a/extapi/openxcas/openxcas_smartcard.h b/extapi/openxcas/openxcas_smartcard.h old mode 100644 new mode 100755 diff --git a/globals.h b/globals.h old mode 100644 new mode 100755 diff --git a/globals.h.bak b/globals.h.bak old mode 100644 new mode 100755 diff --git a/globals.h.orig b/globals.h.orig deleted file mode 100755 index 3790a6f..0000000 --- a/globals.h.orig +++ /dev/null @@ -1,2811 +0,0 @@ -#ifndef GLOBALS_H_ -#define GLOBALS_H_ - -#define _GNU_SOURCE // needed for PTHREAD_MUTEX_RECURSIVE on some plattforms and maybe other things; do not remove -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) -#include -#endif - -/* - * The following hack is taken from Linux: include/linux/kconfig.h - * Original comment follows: - * Getting something that works in C and CPP for an arg that may or may - * not be defined is tricky. Here, if we have "#define CONFIG_BOOGER 1" - * we match on the placeholder define, insert the "0," for arg1 and generate - * the triplet (0, 1, 0). Then the last step cherry picks the 2nd arg (a one). - * When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when - * the last step cherry picks the 2nd arg, we get a zero. - */ -#define __ARG_PLACEHOLDER_1 0, -#define config_enabled(cfg) _config_enabled(cfg) -#define _config_enabled(value) __config_enabled(__ARG_PLACEHOLDER_##value) -#define __config_enabled(arg1_or_junk) ___config_enabled(arg1_or_junk 1, 0) -#define ___config_enabled(__ignored, val, ...) val - -#include "config.h" - -#if defined(WITH_SSL) && !defined(WITH_LIBCRYPTO) -# define WITH_LIBCRYPTO 1 -#endif - -/* For deprecated but still needed cryptography functions: - * 10002 corresponds to OpenSSL version 1.0.2*/ - -#define OPENSSL_API_COMPAT 10002 - -#if defined(__CYGWIN__) || defined(__arm__) || defined(__SH4__) || defined(__MIPS__) || defined(__MIPSEL__) || defined(__powerpc__) -# define CS_LOGFILE "/dev/tty" -#endif - -#if defined(__AIX__) || defined(__SGI__) || defined(__OSF__) || defined(__HPUX__) || defined(__SOLARIS__) || defined(__APPLE__) -# define NEED_DAEMON -#endif - -#if defined(__AIX__) || defined(__SGI__) || defined(__OSF__) || defined(__HPUX__) || defined(__SOLARIS__) || defined(__CYGWIN__) -# define NO_ENDIAN_H -#endif - -#if defined(__AIX__) || defined(__SGI__) -# define socklen_t unsigned long -#endif - -#if defined(__SOLARIS__) || defined(__FreeBSD__) || defined(__OpenBSD__) -# define BSD_COMP -#endif - -#if defined(__HPUX__) -# define _XOPEN_SOURCE_EXTENDED -#endif - -#if (defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)) && !defined(s6_addr32) -#define s6_addr32 __u6_addr.__u6_addr32 -#endif - -#ifdef __ANDROID__ -#ifndef in_port_t -#define in_port_t uint16_t -#endif -#define tcdrain(fd) ioctl(fd, TCSBRK, 1) -#endif - -#ifdef __uClinux__ -#define fork() 0 -#endif - -// Prevent warnings about openssl functions. Apple may consider 'openssl' -// deprecated but changing perfectly working portable code just because they -// introduced some proprietary API is not going to happen. -#if defined(__APPLE__) -#define __AVAILABILITY_MACROS_USES_AVAILABILITY 0 -#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_6 -#endif - -#include "cscrypt/aes.h" - -#ifdef IPV6SUPPORT -#define IN_ADDR_T struct in6_addr -#define SOCKADDR sockaddr_storage -#define ADDR_ANY in6addr_any -#define DEFAULT_AF AF_INET6 -#else -#define IN_ADDR_T in_addr_t -#define SOCKADDR sockaddr_in -#define ADDR_ANY INADDR_ANY -#define DEFAULT_AF AF_INET -#endif - -#ifndef NO_ENDIAN_H -#if defined(__APPLE__) -#include -#define __BYTE_ORDER __DARWIN_BYTE_ORDER -#define __BIG_ENDIAN __DARWIN_BIG_ENDIAN -#define __LITTLE_ENDIAN __DARWIN_LITTLE_ENDIAN -#elif defined(__FreeBSD__) || defined(__OpenBSD__) -#include -#define __BYTE_ORDER _BYTE_ORDER -#define __BIG_ENDIAN _BIG_ENDIAN -#define __LITTLE_ENDIAN _LITTLE_ENDIAN -#else -#include -#include -#endif -#endif - -/* =========================== - * macros - * =========================== */ -// Prevent use of unsafe functions (doesn't work for MacOSX) -#if !defined(__APPLE__) -#define strcpy(a,b) UNSAFE_STRCPY_USE_CS_STRNCPY_INSTEAD() -#define sprintf(a,...) UNSAFE_SPRINTF_USE_SNPRINTF_INSTEAD() -#define strtok(a,b,c) UNSAFE_STRTOK_USE_STRTOK_R_INSTEAD() -#define gmtime(a) UNSAFE_GMTIME_NOT_THREADSAFE_USE_CS_GMTIME_R() -#define localtime(a) UNSAFE_LOCALTIME_NOT_THREADSAFE_USE_LOCALTIME_R() -#define asctime(a) UNSAFE_ASCTIME_NOT_THREADSAFE_USE_ASCTIME_R() -#define ctime(a) UNSAFE_CTIME_NOT_THREADSAFE_USE_CS_CTIME_R() -#define gethostbyaddr(a,b,c) UNSAFE_GETHOSTBYADDR_NOT_THREADSAFE_USE_GETADDRINFO() -#define gethostent(a) UNSAFE_GETHOSTENT_NOT_THREADSAFE() -#define getprotobyname(a) UNSAFE_GETPROTOBYNAME_NOT_THREADSAFE_USE_GETPROTOBYNAME_R() -#define getservbyname(a,b) UNSAFE_GETSERVBYNAME_NOT_THREADSAFE_USE_GETSERVBYNAME_R() -#define getservbyport(a,b) UNSAFE_GETSERVBYPORT_NOT_THREADSAFE_USE_GETSERVBYPORT_R() -#define getservent() UNSAFE_GETSERVENT_NOT_THREADSAFE_USE_GETSERVENT_R() -#define getnetbyname(a) UNSAFE_GETNETBYNAME_NOT_THREADSAFE_USE_GETNETBYNAME_R -#define getnetbyaddr(a,b) UNSAFE_GETNETBYADDR_NOT_THREADSAFE_USE_GETNETBYADDR_R -#define getnetent() UNSAFE_GETNETENT_NOT_THREADSAFE_USE_GETNETENT_R -#define getrpcbyname(a) UNSAFE_GETRPCBYNAME_NOT_THREADSAFE_USE_GETRPCBYNAME_R -#define getrpcbynumber(a) UNSAFE_GETRPCBYNUMBER_NOT_THREADSAFE_USE_GETRPCBYNUMBER_R -#define getrpcent() UNSAFE_GETRPCENT_NOT_THREADSAFE_USE_GETRPCENT_R -#define ctermid(a) UNSAFE_CTERMID_NOT_THREADSAFE_USE_CTERMID_R -#define tmpnam(a) UNSAFE_TMPNAM_NOT_THREADSAFE -#define tempnam(a,b) UNSAFE_TEMPNAM_NOT_THREADSAFE -#define getlogin() UNSAFE_GETLOGIN_NOT_THREADSAFE_USE_GETLOGIN_R -#define getpwnam(a) UNSAFE_GETPWNAM_NOT_THREADSAFE_USE_GETPWNAM_R -#define getpwent() UNSAFE_GETPWENT_NOT_THREADSAFE_USE_GETPWENT_R -#define fgetpwent(a) UNSAFE_FGETPWENT_NOT_THREADSAFE_USE_FGETPWENT_R -#ifndef __ANDROID__ -#define getpwuid(a) UNSAFE_GETPWUID_NOT_THREADSAFE_USE_GETPWUID_R -#endif -#define getspent() UNSAFE_GETSPENT_NOT_THREADSAFE_USE_GETSPENT_R -#define getspnam(a) UNSAFE_GETSPNAM_NOT_THREADSAFE_USE_GETSPNAM_R -#define fgetspent(a) UNSAFE_FGETSPENT_NOT_THREADSAFE_USE_FGETSPENT_R -#define getgrnam(a) UNSAFE_GETGRNAM_NOT_THREADSAFE_USE_GETGRNAM_R -#define getgrent() UNSAFE_GETGRENT_NOT_THREADSAFE_USE_GETGRENT_R -#define getgrgid(a) UNSAFE_GETGRGID_NOT_THREADSAFE_USE_GETGRGID_R -#define fgetgrent() UNSAFE_FGETGRENT_NOT_THREADSAFE_USE_FGETGRGID_R -#define fcvt(a,b,c,d) UNSAFE_FCVT_NOT_THREADSAFE_AND_DEPRECATED -#define ecvt(a,b,c,d) UNSAFE_ECVT_NOT_THREADSAFE_AND_DEPRECATED -#define gcvt(a,b,c) UNSAFE_GCVT_NOT_THREADSAFE_AND_DEPRECATED -#define strptime(a,b,c) STRPTIME_NOT_EXISTS_ON_SOME_DM500_DB2() -#define ftime(a) FTIME_DEPRECATED() -#define timegm(a) TIMEGM_GNU_SPECIFIC_USE_CS_TIMEGM -#endif - -#ifdef UNUSED -#elif __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) -# define UNUSED(x) UNUSED_ ## x __attribute__((unused)) -#elif defined(__LCLINT__) -# define UNUSED(x) /*@unused@*/ x -#else -# define UNUSED(x) x -#endif - -#if __GNUC__ >= 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -# define MUST_CHECK_RESULT __attribute__((warn_unused_result)) -#endif - -#ifdef OK -#undef OK -#endif - -#ifdef ERROR -#undef ERROR -#endif - -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) - -#ifdef WITH_DEBUG -# define call(arg) \ - if(arg) \ - { \ - cs_log_dbg(D_TRACE, "ERROR, function call %s returns error.",#arg); \ - return ERROR; \ - } -#else -# define call(arg) \ - if(arg) \ - { \ - return ERROR; \ - } -#endif - -// checking if (X) free(X) unneccessary since freeing a null pointer doesnt do anything -#define NULLFREE(X) {void *tmpX=X; X=NULL; free(tmpX); } - -#ifdef __CYGWIN__ -#define cs_recv(a,b,c,d) cygwin_recv(a,b,c,d) -#else -#define cs_recv(a,b,c,d) recv(a,b,c,d) -#endif - -// safe wrappers to pthread functions -#define fprintf_stderr(fmt, params...) fprintf(stderr, fmt, ##params) - -#define SAFE_PTHREAD_1ARG(a, b, c) { \ - int32_t pter = a(b); \ - if(pter != 0) \ - { \ - c("FATAL ERROR: %s() failed in %s with error %d %s\n", #a, __func__, pter, strerror(pter)); \ - } } - -#define SAFE_MUTEX_LOCK(a) SAFE_PTHREAD_1ARG(pthread_mutex_lock, a, cs_log) -#define SAFE_MUTEX_UNLOCK(a) SAFE_PTHREAD_1ARG(pthread_mutex_unlock, a, cs_log) -#define SAFE_COND_SIGNAL(a) SAFE_PTHREAD_1ARG(pthread_cond_signal, a, cs_log) -#define SAFE_COND_BROADCAST(a) SAFE_PTHREAD_1ARG(pthread_cond_broadcast, a, cs_log) -#define SAFE_RWLOCK_RDLOCK(a) SAFE_PTHREAD_1ARG(pthread_rwlock_rdlock, a, cs_log) -#define SAFE_RWLOCK_WRLOCK(a) SAFE_PTHREAD_1ARG(pthread_rwlock_wrlock, a, cs_log) -#define SAFE_RWLOCK_UNLOCK(a) SAFE_PTHREAD_1ARG(pthread_rwlock_unlock, a, cs_log) -#define SAFE_ATTR_INIT(a) SAFE_PTHREAD_1ARG(pthread_attr_init, a, cs_log) -#define SAFE_MUTEXATTR_INIT(a) SAFE_PTHREAD_1ARG(pthread_mutexattr_init, a, cs_log) -#define SAFE_CONDATTR_INIT(a) SAFE_PTHREAD_1ARG(pthread_condattr_init, a, cs_log) - -#define SAFE_MUTEX_LOCK_NOLOG(a) SAFE_PTHREAD_1ARG(pthread_mutex_lock, a, fprintf_stderr) -#define SAFE_MUTEX_UNLOCK_NOLOG(a) SAFE_PTHREAD_1ARG(pthread_mutex_unlock, a, fprintf_stderr) -#define SAFE_COND_SIGNAL_NOLOG(a) SAFE_PTHREAD_1ARG(pthread_cond_signal, a, fprintf_stderr) -#define SAFE_MUTEX_UNLOCK_NOLOG(a) SAFE_PTHREAD_1ARG(pthread_mutex_unlock, a, fprintf_stderr) -#define SAFE_ATTR_INIT_NOLOG(a) SAFE_PTHREAD_1ARG(pthread_attr_init, a, fprintf_stderr) -#define SAFE_CONDATTR_INIT_NOLOG(a) SAFE_PTHREAD_1ARG(pthread_condattr_init, a, fprintf_stderr) - -#define SAFE_PTHREAD_2ARG(a, b, c, d) { \ - int32_t pter = a(b, c); \ - if(pter != 0) \ - { \ - d("FATAL ERROR: %s() failed in %s with error %d %s\n", #a, __func__, pter, strerror(pter)); \ - } } - -#define SAFE_COND_WAIT(a,b) SAFE_PTHREAD_2ARG(pthread_cond_wait, a, b, cs_log) -#define SAFE_THREAD_JOIN(a,b) SAFE_PTHREAD_2ARG(pthread_join, a, b, cs_log) -#define SAFE_SETSPECIFIC(a,b) SAFE_PTHREAD_2ARG(pthread_setspecific, a, b, cs_log) -#define SAFE_MUTEXATTR_SETTYPE(a,b) SAFE_PTHREAD_2ARG(pthread_mutexattr_settype, a, b, cs_log) -#define SAFE_MUTEX_INIT(a,b) SAFE_PTHREAD_2ARG(pthread_mutex_init, a, b, cs_log) -#define SAFE_COND_INIT(a,b) SAFE_PTHREAD_2ARG(pthread_cond_init, a, b, cs_log) -#define SAFE_CONDATTR_SETCLOCK(a,b) SAFE_PTHREAD_2ARG(pthread_condattr_setclock, a, b, cs_log) - -#define SAFE_MUTEX_INIT_NOLOG(a,b) SAFE_PTHREAD_2ARG(pthread_mutex_init, a, b, fprintf_stderr) -#define SAFE_COND_INIT_NOLOG(a,b) SAFE_PTHREAD_2ARG(pthread_cond_init, a, b, fprintf_stderr) -#define SAFE_THREAD_JOIN_NOLOG(a,b) SAFE_PTHREAD_2ARG(pthread_join, a, b, fprintf_stderr) -#define SAFE_CONDATTR_SETCLOCK_NOLOG(a,b) SAFE_PTHREAD_2ARG(pthread_condattr_setclock, a, b, fprintf_stderr) - -#define SAFE_PTHREAD_1ARG_R(a, b, c, d) { \ - int32_t pter = a(b); \ - if(pter != 0) \ - { \ - c("FATAL ERROR: %s() failed in %s (called from %s) with error %d %s\n", #a, __func__, d, pter, strerror(pter)); \ - } } - -#define SAFE_MUTEX_LOCK_R(a, b) SAFE_PTHREAD_1ARG_R(pthread_mutex_lock, a, cs_log, b) -#define SAFE_MUTEX_UNLOCK_R(a, b) SAFE_PTHREAD_1ARG_R(pthread_mutex_unlock, a, cs_log, b) -#define SAFE_COND_SIGNAL_R(a, b) SAFE_PTHREAD_1ARG_R(pthread_cond_signal, a, cs_log, b) -#define SAFE_COND_BROADCAST_R(a, b) SAFE_PTHREAD_1ARG_R(pthread_cond_broadcast, a, cs_log, b) -#define SAFE_CONDATTR_INIT_R(a, b) SAFE_PTHREAD_1ARG_R(pthread_condattr_init, a, cs_log, b) - -#define SAFE_MUTEX_LOCK_NOLOG_R(a, b) SAFE_PTHREAD_1ARG_R(pthread_mutex_lock, a, fprintf_stderr, b) -#define SAFE_MUTEX_UNLOCK_NOLOG_R(a, b) SAFE_PTHREAD_1ARG_R(pthread_mutex_unlock, a, fprintf_stderr, b) -#define SAFE_CONDATTR_INIT_NOLOG_R(a, b) SAFE_PTHREAD_1ARG_R(pthread_condattr_init, a, fprintf_stderr, b) - -#define SAFE_PTHREAD_2ARG_R(a, b, c, d, e) { \ - int32_t pter = a(b, c); \ - if(pter != 0) \ - { \ - d("FATAL ERROR: %s() failed in %s (called from %s) with error %d %s\n", #a, __func__, e, pter, strerror(pter)); \ - } } - -#define SAFE_MUTEX_INIT_R(a,b,c) SAFE_PTHREAD_2ARG_R(pthread_mutex_init, a, b, cs_log, c) -#define SAFE_COND_INIT_R(a,b,c) SAFE_PTHREAD_2ARG_R(pthread_cond_init, a, b, cs_log, c) -#define SAFE_CONDATTR_SETCLOCK_R(a,b,c) SAFE_PTHREAD_2ARG(pthread_condattr_setclock, a, b, cs_log, c) - -#define SAFE_MUTEX_INIT_NOLOG_R(a,b,c) SAFE_PTHREAD_2ARG_R(pthread_mutex_init, a, b, fprintf_stderr, c) -#define SAFE_COND_INIT_NOLOG_R(a,b,c) SAFE_PTHREAD_2ARG_R(pthread_cond_init, a, b, fprintf_stderr, c) -#define SAFE_CONDATTR_SETCLOCK_NOLOG_R(a,b,c) SAFE_PTHREAD_2ARG(pthread_condattr_setclock, a, b, fprintf_stderr, c) - -#define SAFE_COND_TIMEDWAIT(a, b, c) { \ - int32_t pter; \ - if((c)->tv_nsec < 0) (c)->tv_nsec = 0; \ - if((c)->tv_nsec > 999999999) (c)->tv_nsec = 999999999; \ - pter = pthread_cond_timedwait(a, b, c); \ - if(pter != 0 && pter != ETIMEDOUT) \ - { \ - cs_log("FATAL ERROR: pthread_cond_timedwait failed in %s with error %d %s\n", __func__, pter, strerror(pter)); \ - } } - -#define SAFE_COND_TIMEDWAIT_R(a, b, c, d) { \ - int32_t pter; \ - if((c)->tv_nsec < 0) (c)->tv_nsec = 0; \ - if((c)->tv_nsec > 999999999) (c)->tv_nsec = 999999999; \ - pter = pthread_cond_timedwait(a, b, c); \ - if(pter != 0 && pter != ETIMEDOUT) \ - { \ - cs_log("FATAL ERROR: pthread_cond_timedwait failed in %s (called from %s) with error %d %s\n", __func__, d, pter, strerror(pter)); \ - } } - -#define SAFE_ATTR_SETSTACKSIZE(a,b) { \ - int32_t pter = pthread_attr_setstacksize(a, b); \ - if(pter != 0) \ - { \ - cs_log("WARNING: pthread_attr_setstacksize() failed in %s with error %d %s\n", __func__, pter, strerror(pter)); \ - } } - -#define SAFE_ATTR_SETSTACKSIZE_NOLOG(a,b) { \ - int32_t pter = pthread_attr_setstacksize(a, b); \ - if(pter != 0) \ - { \ - fprintf_stderr("WARNING: pthread_attr_setstacksize() failed in %s with error %d %s\n", __func__, pter, strerror(pter)); \ - } } - -#ifdef NO_PTHREAD_STACKSIZE -#undef SAFE_ATTR_SETSTACKSIZE -#undef SAFE_ATTR_SETSTACKSIZE_NOLOG -#define SAFE_ATTR_SETSTACKSIZE(a,b) -#define SAFE_ATTR_SETSTACKSIZE_NOLOG(a,b) -#endif - -#define CHECK_BIT(var,pos) (((var) & (1<<(pos)))? 1 : 0) - -// CW VOTING -#define MAX_VOTE_CANDIDATES 16 // Zwiększono dla obsługi większej liczby głosów -#define MIN_VOTES_REQUIRED 2 -#define CW_COMPARE_LEN 14 - -/* =========================== - * constants - * =========================== */ -#define SCM_URL "https://github.com/oscam-mirror/oscam-emu" -#define WIKI_URL "https://git.streamboard.tv/common/oscam/-/wikis" -#define BOARD_URL "https://github.com/oscam-mirror/oscam-emu/discussions" -#ifndef CS_VERSION -#define CS_VERSION "2.26.01-11942" -#endif -#ifndef CS_GIT_COMMIT -#define CS_GIT_COMMIT "a2b4c6d8" -#endif -#ifdef CS_CACHEEX -#ifdef CS_CACHEEX_AIO -#define CS_AIO_VERSION CS_VERSION -#define CS_AIO_VERSION_LEN (sizeof(CS_AIO_VERSION)) -#endif -#endif -#ifndef CS_TARGET -# define CS_TARGET "unknown" -#endif -#ifndef CS_CONFDIR -#define CS_CONFDIR "/usr/local/etc" -#endif -#ifndef CS_LOGFILE -#define CS_LOGFILE "/var/log/oscam.log" -#endif -#define CS_QLEN 128 // size of request queue -#define CS_MAXPROV 32 -#define CS_MAXPORTS 32 // max server ports -#define CS_CLIENT_HASHBUCKETS 32 -#define CS_SERVICENAME_SIZE 32 - -#define CS_ECMSTORESIZE 16 // use MD5() -#define CS_EMMSTORESIZE 16 // use MD5() -#define CS_CLIENT_TIMEOUT 5000 -#define CS_CLIENT_MAXIDLE 120 -#define CS_BIND_TIMEOUT 120 -#define CS_DELAY 0 -#define CS_ECM_RINGBUFFER_MAX 0x10 // max size for ECM last responsetimes ringbuffer. Keep this set to power of 2 values! - -// Support for multiple CWs per channel and other encryption algos -#define WITH_EXTENDED_CW 1 - -#define MAX_ECM_SIZE 1024 -#define MAX_EMM_SIZE 1024 - -#define MAX_CMD_SIZE 0xff + 5 // maximum value from length byte + command header - -#ifdef WITH_EMU -#define CS_EMMCACHESIZE 1024 // nr of EMMs that EMU reader will cache -#else -#define CS_EMMCACHESIZE 512 // nr of EMMs that each reader will cache -#endif -#define MSGLOGSIZE 64 // size of string buffer for a ecm to return messages - -#define D_TRACE 0x0001 // Generate very detailed error/trace messages per routine -#define D_ATR 0x0002 // Debug ATR parsing, dump of ecm, cw -#define D_READER 0x0004 // Debug Reader/Proxy Process -#define D_CLIENT 0x0008 // Debug Client Process -#define D_IFD 0x0010 // Debug IFD+protocol -#define D_DEVICE 0x0020 // Debug Reader I/O -#define D_EMM 0x0040 // Dumps EMM -#define D_DVBAPI 0x0080 // Debug DVBAPI -#define D_LB 0x0100 // Debug Loadbalancer/ECM handler -#define D_CACHEEX 0x0200 // Debug CACHEEX -#define D_CLIENTECM 0x0400 // Debug Client ECMs -#define D_CSP 0x0800 // Debug CSP -#define D_CWC 0x1000 // Debug CWC -#ifdef CS_CACHEEX_AIO -#define D_CW_CACHE 0x2000 // Debug CW Cache -#endif -#define D_ALL_DUMP 0xFFFF // dumps all - -#ifdef CS_CACHEEX_AIO -#define MAX_DEBUG_LEVELS 14 -#else -#define MAX_DEBUG_LEVELS 13 -#endif - -/////// phoenix readers which need baudrate setting and timings need to be guarded by OSCam: BEFORE R_MOUSE -#define R_DB2COM1 0x1 // Reader Dbox2 @ com1 -#define R_DB2COM2 0x2 // Reader Dbox2 @ com1 -#define R_SC8in1 0x3 // Reader Sc8in1 or MCR -#define R_MP35 0x4 // AD-Teknik Multiprogrammer 3.5 and 3.6 (only usb tested) -#define R_MOUSE 0x5 // Reader smartcard mouse -/////// internal readers (Dreambox, Coolstream, IPBox) are all R_INTERNAL, they are determined compile-time -#define R_INTERNAL 0x6 // Reader smartcard intern -#define R_SMART 0x7 // Reader smartcard (generic) -/////// readers that do not reed baudrate setting and timings are guarded by reader itself (large buffer built in): AFTER R_SMART -#define R_PCSC 0x8 // PCSC -#define R_DRECAS 0x9 // Reader DRECAS -#define R_EMU 0x17 // Reader EMU -/////// proxy readers after R_CS378X -#define R_CAMD35 0x20 // Reader cascading camd 3.5x -#define R_CAMD33 0x21 // Reader cascading camd 3.3x -#define R_NEWCAMD 0x22 // Reader cascading newcamd -#define R_RADEGAST 0x23 // Reader cascading radegast -#define R_CS378X 0x24 // Reader cascading camd 3.5x TCP -#define R_CONSTCW 0x25 // Reader for Constant CW -#define R_CSP 0x26 // Cache CSP -#define R_GHTTP 0x27 // Reader ghttp -#define R_SCAM 0x28 // Reader cascading scam -/////// peer to peer proxy readers after R_CCCAM -#define R_GBOX 0x30 // Reader cascading gbox -#define R_CCCAM 0x35 // Reader cascading cccam -#define R_PANDORA 0x36 // Reader cascading pandora -#define R_SERIAL 0x80 // Reader serial -#define R_IS_NETWORK 0x60 -#define R_IS_CASCADING 0xE0 - -#define is_network_reader(__X) (__X->typ & R_IS_NETWORK) -#define is_cascading_reader(__X) (__X->typ & R_IS_CASCADING) -#define is_smargo_reader(__X) (__X->crdr && strcmp(__X->crdr->desc, "smargo") == 0) - -// ECM rc codes: -/////// all found -#define E_FOUND 0 -#define E_CACHE1 1 -#define E_CACHE2 2 -#define E_CACHEEX 3 -/////// all notfound, some error or problem -#define E_NOTFOUND 4 // for selection of found, use < E_NOTFOUND -#define E_TIMEOUT 5 -#define E_SLEEPING 6 -#define E_FAKE 7 -#define E_INVALID 8 -#define E_CORRUPT 9 -#define E_NOCARD 10 -#define E_EXPDATE 11 -#define E_DISABLED 12 -#define E_STOPPED 13 // for selection of error, use <= E_STOPPED and exclude selection of found - -#define E_ALREADY_SENT 101 -#define E_WAITING 102 -#define E_99 99 // this code is undocumented -#define E_UNHANDLED 100 // for selection of unhandled, use >= E_UNHANDLED - -#define CS_MAX_MOD 20 -#define MOD_CONN_TCP 1 -#define MOD_CONN_UDP 2 -#define MOD_CONN_NET 3 -#define MOD_CONN_SERIAL 4 -#define MOD_NO_CONN 8 - -#define EMM_UNIQUE 1 -#define EMM_SHARED 2 -#define EMM_GLOBAL 4 -#define EMM_UNKNOWN 8 - -// Listener Types -#define LIS_CAMD33TCP 1 -#define LIS_CAMD35UDP 2 -#define LIS_CAMD35TCP 4 -#define LIS_NEWCAMD 8 -#define LIS_CCCAM 16 -#define LIS_GBOX 32 -#define LIS_RADEGAST 64 -#define LIS_DVBAPI 128 -#define LIS_CONSTCW 256 -#define LIS_SERIAL 1024 -#define LIS_CSPUDP 2048 -#define LIS_SCAM 4096 - -// EMM types: -#define UNKNOWN 0 -#define UNIQUE 1 -#define SHARED 2 -#define GLOBAL 3 - -#define NCD_AUTO 0 -#define NCD_524 1 -#define NCD_525 2 - -// moved from reader-common.h -#define UNKNOWN 0 -#define CARD_NEED_INIT 1 -#define CARD_INSERTED 2 -#define CARD_FAILURE 3 -#define NO_CARD 4 -#define READER_DEVICE_ERROR 5 - -// moved from stats -#define DEFAULT_REOPEN_SECONDS 30 -#define DEFAULT_MIN_ECM_COUNT 5 -#define DEFAULT_MAX_ECM_COUNT 500 -#define DEFAULT_NBEST 1 -#define DEFAULT_NFB 1 -#define DEFAULT_RETRYLIMIT 0 -#define DEFAULT_LB_MODE 0 -#define DEFAULT_LB_STAT_CLEANUP 336 -#define DEFAULT_UPDATEINTERVAL 240 -#define DEFAULT_LB_AUTO_BETATUNNEL 1 -#define DEFAULT_LB_AUTO_BETATUNNEL_MODE 0 -#define DEFAULT_LB_AUTO_BETATUNNEL_PREFER_BETA 50 - -#define DEFAULT_MAX_CACHE_TIME 15 -#define DEFAULT_MAX_HITCACHE_TIME 15 - -#define DEFAULT_LB_AUTO_TIMEOUT 0 -#define DEFAULT_LB_AUTO_TIMEOUT_P 30 -#define DEFAULT_LB_AUTO_TIMEOUT_T 300 - -enum {E1_GLOBAL = 0, E1_USER, E1_READER, E1_SERVER, E1_LSERVER}; - -// LB blocking events: -enum {E2_GLOBAL = 0, E2_GROUP, E2_CAID, E2_IDENT, E2_CLASS, E2_CHID, E2_QUEUE, E2_OFFLINE, - E2_SID, E2_CCCAM_NOCARD, - // From here only LB nonblocking events: - E2_CCCAM_NOK1, E2_CCCAM_NOK2, E2_CCCAM_LOOP, E2_WRONG_CHKSUM, E2_RATELIMIT - }; - -#define LB_NONBLOCK_E2_FIRST E2_CCCAM_NOK1 - -#define CTA_RES_LEN 512 - -#define MAX_ATR_LEN 33 // max. ATR length -#define MAX_HIST 15 // max. number of historical characters - -#define MAX_SIDBITS 64 // max services -#define SIDTABBITS uint64_t // 64bit type for services, if a system does not support this type, -// please use a define and define it as uint32_t / MAX_SIDBITS 32 - -#define BAN_UNKNOWN 1 // Failban mask for anonymous/ unknown contact -#define BAN_DISABLED 2 // Failban mask for Disabled user -#define BAN_SLEEPING 4 // Failban mask for sleeping user -#define BAN_DUPLICATE 8 // Failban mask for duplicate user - -#define MAX_HTTP_DYNDNS 3 // maximum allowed Dyndns addresses for webif access - -#define CHECK_WAKEUP 1 -#define CHECK_ANTICASCADER 2 -#define CHECK_ECMCACHE 3 - -#define AVAIL_CHECK_CONNECTED 0 -#define AVAIL_CHECK_LOADBALANCE 1 - -#define ECM_FMT_LEN 109 // 64 -#define CXM_FMT_LEN 209 // 160 - -#define LB_MAX_STAT_TIME 10 - -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) -#define OSCAM_SIGNAL_WAKEUP SIGCONT -#else -#define OSCAM_SIGNAL_WAKEUP SIGRTMAX-2 -#endif - -#define READER_ACTIVE 0x01 -#define READER_FALLBACK 0x02 -#define READER_LOCAL 0x04 -#define READER_CACHEEX 0x08 - -#define REQUEST_SENT 0x10 -#define REQUEST_ANSWERED 0x20 - -#define CW_MODE_ONE_CW 0 -#define CW_MODE_MULTIPLE_CW 1 -#define CW_TYPE_VIDEO 0 -#define CW_TYPE_AUDIO 1 -#define CW_TYPE_DATA 2 -#define CW_ALGO_CSA 0 -#define CW_ALGO_DES 1 -#define CW_ALGO_AES128 2 -#define CW_ALGO_CSA_ALT 3 -#define CW_ALGO_MODE_ECB 0 -#define CW_ALGO_MODE_CBC 1 - -#define SIZE_SHORTDAY 8 -#define MAXALLOWEDTF 1001 // 10 allowed time frame slots for everyday + all [(3 + 1 + 10*(12) + 1)*8] -extern const char *shortDay[SIZE_SHORTDAY]; -extern const char *weekdstr; - -/* =========================== - * Default Values - * =========================== */ -#define DEFAULT_INACTIVITYTIMEOUT 0 -#define DEFAULT_TCP_RECONNECT_TIMEOUT 30 -#define DEFAULT_NCD_KEEPALIVE 0 - -#define DEFAULT_CC_MAXHOPS 10 -#define DEFAULT_CC_RESHARE -1 // Use global cfg -#define DEFAULT_CC_IGNRSHR -1 // Use global cfg -#define DEFAULT_CC_STEALTH -1 // Use global cfg -#define DEFAULT_CC_KEEPALIVE 0 -#define DEFAULT_CC_RECONNECT 12000 -#define DEFAULT_CC_RECV_TIMEOUT 2000 - -#define DEFAULT_AC_USERS -1 // Use global cfg -#define DEFAULT_AC_PENALTY -1 // Use global cfg - -// Return MPEG section length -#define SCT_LEN(sct) (3+((sct[1]&0x0f)<<8)+sct[2]) -// Used by readers -#define MAX_LEN 256 - -#define NO_CAID_VALUE 0xfffe -#define NO_PROVID_VALUE 0xfffffe -#define NO_SRVID_VALUE 0xfffe - -// If NULL return empty string -#define ESTR(x) ((x) ? (x) : "") - -#ifndef MAX -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#endif - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -/* - See: http://stackoverflow.com/questions/10269685/kernels-container-of-any-way-to-make-it-iso-conforming - http://www.kroah.com/log/linux/container_of.html -*/ -#define container_of(ptr, type, member) \ - ((type *) ((char *) (ptr) - offsetof(type, member) + \ - (&((type *) 0)->member == (ptr)) * 0)) - -/* =========================== - * global structures - * =========================== */ -struct timeb -{ - time_t time; - int64_t millitm; -}; - -typedef struct cs_mutexlock -{ - int32_t timeout; - pthread_mutex_t lock; - pthread_cond_t writecond, readcond; - const char *name; - int8_t flag; - int16_t writelock, readlock; -} CS_MUTEX_LOCK; - -#include "oscam-llist.h" - -typedef struct s_caidvaluetab_data -{ - uint16_t caid; - uint16_t value; -} CAIDVALUETAB_DATA; - -typedef struct s_caidvaluetab -{ - int32_t cvnum; - CAIDVALUETAB_DATA *cvdata; -} CAIDVALUETAB; - -typedef struct s_classtab -{ - uint8_t an; - uint8_t bn; - uint8_t *aclass; - uint8_t *bclass; -} CLASSTAB; - -typedef struct s_caidtab_data -{ - uint16_t caid; - uint16_t mask; - uint16_t cmap; -} CAIDTAB_DATA; - -typedef struct s_caidtab -{ - int32_t ctnum; - CAIDTAB_DATA *ctdata; -} CAIDTAB; - -typedef struct s_tuntab_data -{ - uint16_t bt_caidfrom; - uint16_t bt_caidto; - uint16_t bt_srvid; -} TUNTAB_DATA; - -typedef struct s_tuntab -{ - int32_t ttnum; - TUNTAB_DATA *ttdata; -} TUNTAB; - -typedef struct s_sidtab -{ - char label[64]; -#ifdef CS_CACHEEX_AIO - uint8_t disablecrccws_only_for_exception; - uint8_t no_wait_time; - uint8_t lg_only_exception; -#endif - uint16_t num_caid; - uint16_t num_provid; - uint16_t num_srvid; - uint16_t *caid; - uint32_t *provid; - uint16_t *srvid; - struct s_sidtab *next; -} SIDTAB; - -typedef struct s_filter -{ - uint16_t caid; - uint8_t nprids; - uint32_t prids[CS_MAXPROV]; -} FILTER; - -typedef struct s_ftab -{ - int32_t nfilts; - FILTER *filts; -} FTAB; - -typedef struct s_ncd_ftab -{ - int32_t nfilts; - FILTER filts[16]; -} NCD_FTAB; - -struct ncd_port -{ - bool ncd_key_is_set; - uint8_t ncd_key[14]; - NCD_FTAB ncd_ftab; -}; - -typedef struct s_port -{ - int32_t fd; - int32_t s_port; - struct ncd_port *ncd; // newcamd specific settings -} PORT; - -typedef struct s_ptab -{ - int32_t nports; - PORT ports[CS_MAXPORTS]; -} PTAB; - -typedef struct aes_entry -{ - uint16_t keyid; - uint16_t caid; - uint32_t ident; - uint8_t plainkey[16]; - AES_KEY key; - struct aes_entry *next; -} AES_ENTRY; - -struct aes_keys -{ - AES_KEY aeskey_encrypt; // encryption key needed by monitor and used by camd33, camd35 - AES_KEY aeskey_decrypt; // decryption key needed by monitor and used by camd33, camd35 -}; - -struct s_ecm -{ - uint8_t ecmd5[CS_ECMSTORESIZE]; - uint8_t cw[16]; - uint16_t caid; - uint64_t grp; - struct s_reader *reader; - int32_t rc; - time_t time; -}; - -struct s_emmstat -{ - uint8_t emmd5[CS_EMMSTORESIZE]; - uint8_t type; - int32_t count; - struct timeb firstwritten; - struct timeb lastwritten; -}; - -struct s_emmcache -{ - uint8_t emmd5[CS_EMMSTORESIZE]; - uint8_t type; - uint16_t len; - uint8_t emm[MAX_EMM_SIZE]; - struct timeb firstseen; - struct timeb lastseen; -}; - -struct s_csystem_emm_filter -{ - uint8_t type; - uint8_t enabled; - uint8_t filter[16]; - uint8_t mask[16]; -}; - -typedef struct v_ban // Failban listmember -{ - int32_t v_count; - IN_ADDR_T v_ip; - int32_t v_port; - struct timeb v_time; - bool acosc_entry; - int32_t acosc_penalty_dur; - char *info; -} V_BAN; - -typedef struct s_cacheex_stat_entry // Cacheex stats listmember -{ - int32_t cache_count; - time_t cache_last; - uint16_t cache_caid; - uint16_t cache_srvid; - uint32_t cache_prid; - int8_t cache_direction; // 0 = push / 1 = got -#ifdef CS_CACHEEX_AIO - int32_t cache_count_lg; -#endif -} S_CACHEEX_STAT_ENTRY; - -typedef struct s_entitlement // contains entitlement Info -{ - uint64_t id; // the element ID - uint32_t type; // enumerator for tier,chid whatever - // 0="", 1="Package", 2="PPV-Event", 3="chid", 4="tier", 5 = "class", 6 = "PBM". 7 = "seca-admin" - uint16_t caid; // the caid of element - uint32_t provid; // the provid of element - uint32_t class; // the class needed for some systems - time_t start; // startdate - time_t end; // enddate -#ifdef WITH_EMU - bool isKey; - bool isData; - char name[8]; - uint8_t *key; - uint32_t keyLength; -#endif -} S_ENTITLEMENT; - -struct s_client; -struct ecm_request_t; -struct emm_packet_t; -struct cmd_packet_t; -struct s_ecm_answer; -struct demux_s; - -#define DEFAULT_MODULE_BUFsize 1024 - -struct s_module -{ - const char *desc; - int8_t type; - int8_t large_ecm_support; - int16_t listenertype; - //int32_t s_port; - IN_ADDR_T s_ip; - uint16_t bufsize; - void *(*s_handler)(struct s_client *, uint8_t *, int32_t); - void (*s_init)(struct s_client *); - int32_t (*recv)(struct s_client *, uint8_t *, int32_t); - void (*send_dcw)(struct s_client *, struct ecm_request_t *); - void (*cleanup)(struct s_client *); - int32_t (*c_recv_chk)(struct s_client *, uint8_t *, int32_t *, uint8_t *, int32_t); - int32_t (*c_init)(struct s_client *); - int32_t (*c_send_ecm)(struct s_client *, struct ecm_request_t *); - int32_t (*c_send_emm)(struct emm_packet_t *); - int32_t (*c_available)(struct s_reader *, int32_t, struct ecm_request_t *); // Schlocke: available check for load-balancing, - // params: - // rdr (reader to check) - // int32_t checktype (0=return connected, 1=return loadbalance-avail) return int - void (*c_idle)(void); // Schlocke: called when reader is idle - void (*s_idle)(struct s_client *); - void (*s_peer_idle)(struct s_client *); - void (*c_card_info)(void); // Schlocke: request card infos - - int32_t (*c_capmt)(struct s_client *, struct demux_s *); - -#ifdef CS_CACHEEX - int32_t (*c_cache_push)(struct s_client *, struct ecm_request_t *); // Cache push - int32_t (*c_cache_push_chk)(struct s_client *, struct ecm_request_t *); // Cache push Node Check, 0=no push -#endif - int32_t c_port; - PTAB ptab; - int32_t num; -}; - -struct s_ATR; - -struct s_cardreader_settings -{ - uint32_t ETU; - uint32_t EGT; - uint8_t P; - uint32_t I; - uint32_t F; - uint32_t Fi; - uint8_t Di; - uint8_t Ni; - uint32_t WWT; - uint32_t BGT; - uint8_t D; -}; - -struct s_cardreader -{ - const char *desc; - int32_t (*reader_init)(struct s_reader *); - int32_t (*get_status)(struct s_reader *, int *); - int32_t (*activate)(struct s_reader *, struct s_ATR *); - int32_t (*transmit)(struct s_reader *, uint8_t *sent, uint32_t size, uint32_t expectedlen, uint32_t delay, uint32_t timeout); - int32_t (*receive)(struct s_reader *, uint8_t *data, uint32_t size, uint32_t delay, uint32_t timeout); - int32_t (*lock_init)(struct s_reader *); - void (*lock)(struct s_reader *); - void (*unlock)(struct s_reader *); - int32_t (*close)(struct s_reader *); - int32_t (*set_parity)(struct s_reader *, uint8_t parity); - int32_t (*write_settings)(struct s_reader *, struct s_cardreader_settings *s); - int32_t (*set_protocol)(struct s_reader *, uint8_t *params, uint32_t *length, uint32_t len_request); - int32_t (*set_baudrate)(struct s_reader *, uint32_t baud); // set only for readers which need baudrate setting and timings need to be guarded by OSCam - int32_t (*card_write)(struct s_reader *pcsc_reader, const uint8_t *buf, uint8_t *cta_res, uint16_t *cta_lr, int32_t l); - void (*display_msg)(struct s_reader *, char *msg); - - int32_t (*do_reset)(struct s_reader *, struct s_ATR *, int32_t (*rdr_activate_card)(struct s_reader *, struct s_ATR *, uint16_t deprecated), int32_t (*rdr_get_cardsystem)(struct s_reader *, struct s_ATR *)); - - bool (*set_DTS_RTS)(struct s_reader *, int32_t *dtr, int32_t *rts); - - int32_t typ; // fixme: workaround, remove when all old code is converted - - int8_t max_clock_speed; // 1 for reader->typ > R_MOUSE - int8_t need_inverse; // 0 = reader does inversing; 1 = inversing done by oscam - //io_serial config - int8_t flush; - int8_t read_written; // 1 = written bytes has to read from device - bool skip_extra_atr_parsing; - bool skip_t1_command_retries; - bool skip_setting_ifsc; -}; - -struct s_cardsystem -{ - const char *desc; - const uint16_t *caids; - int32_t (*card_init)(struct s_reader *reader, struct s_ATR *); - void (*card_done)(struct s_reader *reader); - int32_t (*card_info)(struct s_reader *); - void (*poll_status)(struct s_reader *); - int32_t (*do_ecm)(struct s_reader *, const struct ecm_request_t *, struct s_ecm_answer *); - int32_t (*do_emm_reassembly)(struct s_reader *, struct s_client *, struct emm_packet_t *); // Returns 1/true if the EMM is ready to be written in the card - int32_t (*do_emm)(struct s_reader *, struct emm_packet_t *); - int32_t (*do_rawcmd)(struct s_reader *, struct cmd_packet_t *); - void (*post_process)(struct s_reader *); - int32_t (*get_emm_type)(struct emm_packet_t *, struct s_reader *); - int32_t (*get_emm_filter)(struct s_reader *, struct s_csystem_emm_filter **, uint32_t *); - int32_t (*get_emm_filter_adv)(struct s_reader *, struct s_csystem_emm_filter **, uint32_t *, uint16_t, uint32_t, uint16_t, uint16_t, uint16_t, uint32_t); - int32_t (*get_tunemm_filter)(struct s_reader *, struct s_csystem_emm_filter **, uint32_t *); -}; - -typedef struct cw_extendted_t -{ -#ifdef WITH_EXTENDED_CW - uint8_t mode; - uint8_t audio[4][16]; // 4 x odd/even pairs of 8 byte CWs - uint8_t data[16]; // odd/even pair of 8 byte CW or 16 byte IV - uint8_t session_word[32]; // odd/even pair of 16 byte CW - uint8_t algo; // CSA, DES or AES128 - uint8_t algo_mode; // ECB or CBC -#else - uint8_t disabled; -#endif -} EXTENDED_CW; - -typedef struct s_cw_vote { - uint8_t cw[16]; - uint8_t votes; - uint8_t local_votes; - struct s_reader *voters[MAX_VOTE_CANDIDATES]; -} s_cw_vote; - -// CW Vote settings -typedef struct s_cw_vote_caid_data -{ - uint16_t caid; -} CW_VOTE_CAID_DATA; - -typedef struct s_cw_vote_caid_tab -{ - int32_t cvcnum; - CW_VOTE_CAID_DATA *cvcdata; -} CW_VOTE_CAID_TAB; - -typedef struct ecm_request_t -{ - uint8_t ecm[MAX_ECM_SIZE]; - uint8_t cw[16]; - EXTENDED_CW cw_ex; - uint8_t ecmd5[CS_ECMSTORESIZE]; - int16_t ecmlen; - uint16_t caid; - uint16_t ocaid; // original caid, used for betatunneling - uint16_t srvid; - uint16_t onid; - uint16_t tsid; - uint16_t pmtpid; - uint32_t ens; // enigma namespace - uint32_t vpid; // videopid - uint16_t chid; - uint16_t pid; - uint16_t idx; - uint32_t prid; - struct s_reader *selected_reader; - struct s_ecm_answer *matching_rdr; // list of matching readers - const struct s_reader *fallback; // fallback is the first fallback reader in the list matching_rdr - struct s_client *client; // contains pointer to 'c' client while running in 'r' client - uint64_t grp; - int32_t msgid; // client pending table index - uint8_t stage; // processing stage in server module - int8_t rc; - uint8_t rcEx; - struct timeb tps; // incoming time stamp - int8_t btun; // mark er as betatunneled - uint16_t reader_avail; // count of available readers for ecm - uint16_t readers; // count of available used readers for ecm - uint16_t reader_requested; // count of real requested readers - uint16_t localreader_count; // count of selected local readers - uint16_t cacheex_reader_count; // count of selected cacheex mode-1 readers - uint16_t fallback_reader_count; // count of selected fb readers - uint16_t reader_count; // count of selected not fb readers - int8_t preferlocalcards; - int8_t checked; // for doublecheck - uint8_t cw_checked[16]; // for doublecheck - int8_t readers_timeout_check; // set to 1 after ctimeout occurs and readers not answered are checked - uint32_t client_timeout; // clienttimeout per CAID - struct s_reader *origin_reader; - -#if defined MODULE_CCCAM - void *origin_card; // CCcam preferred card! -#endif - -#if defined MODULE_GBOX - uint32_t gbox_crc; // rcrc for gbox, used to identify ECM task in peer responses - uint16_t gbox_cw_src_peer; - uint16_t gbox_ecm_src_peer; - uint8_t gbox_ecm_dist; - uint8_t gbox_ecm_status; - LLIST *gbox_cards_pending; // type gbox_card_pending -#endif - - void *src_data; - uint32_t csp_hash; // csp has its own hash - - struct s_client *cacheex_src; // Cacheex origin -#ifdef CS_CACHEEX - int8_t cacheex_pushed; // to avoid duplicate pushs - uint8_t csp_answered; // =1 if er get answer by csp - LLIST *csp_lastnodes; // last 10 Cacheex nodes atm cc-proto-only - uint32_t cacheex_wait_time; // cacheex wait time in ms - uint8_t cacheex_wait_time_expired; // =1 if cacheex wait_time expires - uint16_t cacheex_mode1_delay; // cacheex mode 1 delay - uint8_t cacheex_hitcache; // =1 if wait_time due hitcache - void *cw_cache; // pointer to cw stored in cache -#endif -#ifdef CS_CACHEEX_AIO - int32_t ecm_time; // ecm-time in ms - uint8_t localgenerated; // flag for local generated CW -#endif - uint32_t cw_count; - uint8_t from_csp; // =1 if er from csp cache - uint8_t from_cacheex; // =1 if er from cacheex client pushing cache - uint8_t from_cacheex1_client; // =1 if er from cacheex-1 client - char msglog[MSGLOGSIZE]; - uint8_t cwc_cycletime; - uint8_t cwc_next_cw_cycle; -#ifdef CW_CYCLE_CHECK - char cwc_msg_log[MSGLOGSIZE]; -#endif -#ifdef WITH_STAPI5 - char dev_name[20]; -#endif - struct ecm_request_t *parent; - struct ecm_request_t *next; -#ifdef HAVE_DVBAPI - uint8_t adapter_index; -#endif - uint32_t vote_pool_session; // sesja dla vote_pool - zapobiega wielokrotnemu czyszczeniu - struct s_cw_vote vote_pool[MAX_VOTE_CANDIDATES]; -} ECM_REQUEST; - -struct s_ecm_answer -{ - uint8_t status; - struct s_reader *reader; - ECM_REQUEST *er; - int8_t rc; - uint8_t rcEx; - uint8_t cw[16]; - EXTENDED_CW cw_ex; - char msglog[MSGLOGSIZE]; - struct timeb time_request_sent; // using for evaluate ecm_time - int32_t ecm_time; - uint16_t tier; // only filled by local videoguard reader atm -#ifdef WITH_LB - int32_t value; - int32_t time; -#endif - struct s_ecm_answer *next; - CS_MUTEX_LOCK ecmanswer_lock; - struct s_ecm_answer *pending; - struct s_ecm_answer *pending_next; - bool is_pending; -}; - -struct s_acasc_shm -{ - uint16_t ac_count : 15; - uint16_t ac_deny : 1; -}; - -struct s_acasc -{ - uint16_t stat[10]; - uint8_t idx; // current active index in stat[] -}; - -struct s_cwresponse -{ - int32_t duration; - time_t timestamp; - int32_t rc; -}; - -struct s_cascadeuser -{ - uint16_t caid; - uint32_t prid; - uint16_t srvid; - time_t time; - int8_t cwrate; -}; - -typedef struct sidtabs -{ - SIDTABBITS ok; // positive services - SIDTABBITS no; // negative services -} SIDTABS; - -struct s_zap_list -{ - uint16_t caid; - uint32_t provid; - uint16_t chid; - uint16_t sid; - int8_t request_stage; - time_t lasttime; -}; - -// EMM reassemply -struct emm_rass -{ - int16_t emmlen; - int32_t provid; - uint8_t emm[MAX_EMM_SIZE]; -}; - -struct s_client -{ - uint32_t tid; - int8_t init_done; - pthread_mutex_t thread_lock; - int8_t thread_active; - int8_t kill; - int8_t kill_started; - LLIST *joblist; - IN_ADDR_T ip; - in_port_t port; - time_t login; // connection - time_t logout; // disconnection - time_t last; - time_t lastswitch; - time_t lastemm; - time_t lastecm; - time_t expirationdate; - uint32_t allowedtimeframe[SIZE_SHORTDAY][24][2]; // day[0-sun to 6-sat, 7-ALL],hours,minutes use as binary flags to reduce mem usage - uint8_t allowedtimeframe_set; // flag for internal use to mention if allowed time frame is used - int8_t c35_suppresscmd08; - uint8_t c35_sleepsend; - int8_t ncd_keepalive; - int8_t disabled; - uint64_t grp; - int8_t crypted; - int8_t dup; - LLIST *aureader_list; - int8_t autoau; - LLIST *ra_buf; // EMM reassembly buffer for viaccess - struct emm_rass *cw_rass; // EMM reassembly buffer for cryptoworks - int8_t monlvl; - CAIDTAB ctab; - TUNTAB ttab; - SIDTABS sidtabs; - SIDTABS lb_sidtabs; - int8_t typ; // first s_client is type s=starting (master) thread; type r = physical reader, type p = proxy reader both always have 1 s_reader struct allocated; type c = client (user logging in into oscam) type m = monitor type h = http server a = anticascader - uint8_t module_idx; - uint16_t last_srvid; - uint32_t last_provid; - uint16_t last_caid; - struct s_provid *last_providptr; - struct s_srvid *last_srvidptr; - uint32_t last_srvidptr_search_provid; - int32_t tosleep; - struct s_auth *account; - int32_t udp_fd; - struct SOCKADDR udp_sa; - socklen_t udp_sa_len; - int8_t tcp_nodelay; - int8_t log; - int32_t logcounter; - int32_t cwfound; // count found ECMs per client - int32_t cwcache; // count ECMs from cache1/2 per client - int32_t cwnot; // count not found ECMs per client - int32_t cwtun; // count betatunneled ECMs per client - int32_t cwignored; // count ignored ECMs per client - int32_t cwtout; // count timeouted ECMs per client - int32_t cwlastresptime; // last Responsetime (ms) -#ifdef CW_CYCLE_CHECK - int32_t cwcycledchecked; // count checked cwcycles per client - int32_t cwcycledok; // count pos checked cwcycles per client - int32_t cwcyclednok; // count neg checked cwcycles per client - int32_t cwcycledign; // count ign cwcycles per client -#endif - int32_t emmok; // count EMM ok - int32_t emmnok; // count EMM nok - int8_t pending; // number of ECMs pending -#ifdef CS_CACHEEX - int32_t cwcacheexpush; // count pushed ecms/cws - int32_t cwcacheexgot; // count got ecms/cws - int32_t cwcacheexhit; // count hit ecms/cws - LLIST *ll_cacheex_stats; // list for Cacheex statistics - int8_t cacheex_maxhop; - int32_t cwcacheexerr; // cw=00 or chksum wrong - int32_t cwcacheexerrcw; // same Hex, different CW - int16_t cwcacheexping; // peer ping in ms, only used by csp - int32_t cwc_info; // count of in/out comming cacheex ecms with CWCinfo - uint8_t cxnodeid_last[9]; // save previous nodeid - uint8_t cxnodeid_changer_detected; // save node-changer detection status -#ifdef CS_CACHEEX_AIO - int32_t cwcacheexgotlg; // count got localgenerated-flagged CWs - int32_t cwcacheexpushlg; // count pushed localgenerated-flagged CWs -#endif - uint8_t cacheex_needfilter; // flag for cachex mode 3 used with camd35 -#ifdef CS_CACHEEX_AIO - uint8_t cacheex_aio_checked; // flag for cacheex aio detection done -#endif -#endif -#ifdef CS_ANTICASC - struct s_zap_list client_zap_list[15]; // 15 last zappings from client used for ACoSC -#endif -#ifdef WEBIF - struct s_cwresponse cwlastresptimes[CS_ECM_RINGBUFFER_MAX]; // ringbuffer for last 20 times - int32_t cwlastresptimes_last; // ringbuffer pointer - int8_t wihidden; // hidden in webinterface status - char lastreader[64]; // last cw got from this reader -#endif - - uint8_t ucrc[4]; // needed by monitor and used by camd35 - uint32_t pcrc; // password crc - struct aes_keys *aes_keys; // used by camd33 and camd35 - uint16_t ncd_msgid; - uint16_t ncd_client_id; - uint8_t ncd_skey[16]; // Also used for camd35 Cacheex to store remote node id - -#ifdef MODULE_CCCAM - void *cc; -#endif - -#ifdef CS_CACHEEX_AIO -#if defined(MODULE_CAMD35) || defined(MODULE_CAMD35_TCP) - uint8_t c35_extmode; -#endif -#endif - -#ifdef MODULE_GBOX - void *gbox; - uint16_t gbox_peer_id; -#endif - -#ifdef MODULE_GHTTP - void *ghttp; -#endif - - int32_t port_idx; // index in server ptab - int32_t ncd_server; // newcamd server - -#ifdef CS_ANTICASC - int32_t ac_fakedelay; // When this is -1, the global ac_fakedelay is used - uint16_t ac_limit; - int8_t ac_penalty; - struct s_acasc_shm acasc; -#endif - - FTAB fchid; - FTAB ftab; // user [caid] and ident filter - CLASSTAB cltab; - - int32_t pfd; // Primary FD, must be closed on exit - struct s_reader *reader; // points to s_reader when cl->typ='r' - - ECM_REQUEST *ecmtask; - - pthread_t thread; - -#ifdef MODULE_SERIAL - struct s_serial_client *serialdata; -#endif - // reader common - int32_t last_idx; - uint16_t idx; - - int8_t ncd_proto; - uint8_t ncd_header[12]; - - // camd35 - uint8_t upwd[64]; - int8_t is_udp; - int8_t stopped; - uint16_t lastcaid; - uint16_t lastsrvid; - int32_t lastpid; - int8_t disable_counter; - uint8_t lastserial[8]; - - // Failban value set bitwise - compared with BAN_ - int32_t failban; - - LLIST *cascadeusers; // s_cascadeuser - - int32_t n_request[2]; // count for number of request per minute by client - - void *work_mbuf; // Points to local data allocated in work_thread when the thread is running - void *work_job_data; // Points to current job_data when work_thread is running - -#ifdef MODULE_PANDORA - int32_t pand_autodelay; - uint8_t pand_send_ecm; - uint8_t pand_ignore_ecm; - uint8_t pand_md5_key[16]; -#endif - -#ifdef MODULE_SCAM - void *scam; -#endif - void *module_data; // private module data - - struct s_client *next; // make client a linked list - struct s_client *nexthashed; - - int8_t start_hidecards; -}; - -typedef struct s_ecm_whitelist_data -{ - uint16_t len; - uint16_t caid; - uint32_t ident; -} ECM_WHITELIST_DATA; - -typedef struct s_ecm_whitelist -{ - int32_t ewnum; - ECM_WHITELIST_DATA *ewdata; -} ECM_WHITELIST; - -typedef struct s_ecm_hdr_whitelist_data -{ - uint16_t len; - uint16_t caid; - uint32_t provid; - uint8_t header[20]; -} ECM_HDR_WHITELIST_DATA; - -typedef struct s_ecm_hdr_whitelist -{ - int32_t ehnum; - ECM_HDR_WHITELIST_DATA *ehdata; -} ECM_HDR_WHITELIST; - -// ratelimit -struct ecmrl -{ - struct timeb last; - uint8_t kindecm; - bool once; - uint8_t ecmd5[CS_ECMSTORESIZE]; - uint16_t caid; - uint32_t provid; - uint16_t srvid; - uint16_t chid; - int32_t ratelimitecm; - int32_t ratelimittime; - int32_t srvidholdtime; -}; -#define MAXECMRATELIMIT 20 - -// maxparallel service tracking -struct s_parallel_slot -{ - uint16_t srvid; // service ID - struct timeb last_ecm; // time of last ECM for this service - int32_t ecm_interval; // measured interval between ECMs in ms - struct s_client *client; // client using this slot -}; - -// maxparallel blocked client tracking -struct s_blocked_client -{ - struct s_client *client; // client pointer - uint16_t srvid; // blocked service ID -}; - -#ifdef MODULE_SERIAL -struct ecmtw -{ - uint16_t caid; - uint32_t provid; - uint16_t srvid; - uint16_t deg; - uint16_t freq; -}; -#endif - -typedef struct ce_csp_tab_data -{ - int32_t caid; - int32_t cmask; - int32_t prid; - int32_t srvid; - int16_t awtime; - int16_t dwtime; -} CECSPVALUETAB_DATA; - -typedef struct ce_csp_tab -{ - int32_t cevnum; - CECSPVALUETAB_DATA *cevdata; -} CECSPVALUETAB; - -typedef struct cacheex_check_cw_tab_data -{ - int32_t caid; - int32_t cmask; - int32_t prid; - int32_t srvid; - int8_t mode; - uint32_t counter; -} CWCHECKTAB_DATA; - -typedef struct cacheex_check_cw_tab -{ - int32_t cwchecknum; - CWCHECKTAB_DATA *cwcheckdata; - -} CWCHECKTAB; - -typedef struct cacheex_check_cw -{ - int8_t mode; - uint32_t counter; -} CWCHECK; - -typedef struct ce_csp_t -{ - int8_t mode; - int8_t maxhop; -#ifdef CS_CACHEEX_AIO - int8_t maxhop_lg; -#endif - CECSPVALUETAB filter_caidtab; - CAIDVALUETAB cacheex_nopushafter_tab; - uint8_t allow_request; - uint8_t allow_reforward; - uint8_t drop_csp; - uint8_t allow_filter; -#ifdef CS_CACHEEX_AIO - uint8_t allow_maxhop; -#endif - uint8_t block_fakecws; -#ifdef CS_CACHEEX_AIO - uint8_t cw_check_for_push; - uint8_t localgenerated_only; - CAIDTAB localgenerated_only_caidtab; - FTAB lg_only_tab; - uint8_t localgenerated_only_in; - CAIDTAB localgenerated_only_in_caidtab; - FTAB lg_only_in_tab; - uint8_t lg_only_in_aio_only; - uint8_t lg_only_remote_settings; - int32_t feature_bitfield; - char aio_version[CS_AIO_VERSION_LEN]; -#endif -} CECSP; - -struct s_emmlen_range -{ - int16_t min; - int16_t max; -}; - -typedef struct emm_packet_t -{ - uint8_t emm[MAX_EMM_SIZE]; - int16_t emmlen; - uint8_t caid[2]; - uint8_t provid[4]; - uint8_t hexserial[8]; // contains hexserial or SA of EMM - uint8_t type; - uint8_t skip_filter_check; - struct s_client *client; -} EMM_PACKET; - -typedef struct cmd_packet_t -{ - uint8_t cmd[MAX_CMD_SIZE]; - int16_t cmdlen; - struct s_client *client; -} CMD_PACKET; - -struct s_reader // contains device info, reader info and card info -{ - uint8_t keepalive; - uint8_t changes_since_shareupdate; - int32_t resetcycle; // ECM until reset - int32_t resetcounter; // actual count - uint32_t auprovid; // AU only for this provid - int8_t audisabled; // exclude reader from auto AU - struct timeb emm_last; // time of last successfully written emm - struct s_client *client; // pointer to 'r'client this reader is running in - LLIST *ll_entitlements; // entitlements - int8_t enable; - int8_t active; - int8_t dropbadcws; // Schlocke: 1=drops cw if checksum is wrong. 0=fix checksum (default) - int8_t disablecrccws; // 1=disable cw checksum test. 0=enable checksum check - uint64_t grp; - int8_t fallback; - FTAB fallback_percaid; - FTAB localcards; - FTAB disablecrccws_only_for; // ignore checksum for selected caid provid -#ifdef READER_CRYPTOWORKS - int8_t needsglobalfirst; // 0:Write one Global EMM for SHARED EMM disabled 1:Write one Global EMM for SHARED EMM enabled -#endif -#if defined(READER_NAGRA) - uint8_t cak63nuid[4]; - uint8_t cak63nuid_length; - uint8_t cak63cwekey[16]; - uint8_t cak63cwekey_length; -#endif -#ifdef READER_NAGRA_MERLIN - uint8_t mod1[112]; - uint8_t mod1_length; - uint8_t cmd0eprov[2]; - uint8_t cmd0eprov_length; - uint8_t mod2[112]; - uint8_t mod2_length; - uint8_t tmprsa[112]; - uint8_t data50[80]; - uint8_t data50_length; - uint8_t mod50[80]; - uint8_t mod50_length; - uint8_t key3588[136]; - uint8_t key3588_length; - uint8_t key60[96]; - uint8_t exp60[96]; - uint8_t key68[104]; - uint8_t exp68[104]; - uint8_t key3des[16]; - uint8_t klucz68[24]; - uint8_t pairtype; - uint8_t hasunique; - uint8_t key3460[96]; - uint8_t key3460_length; - uint8_t key3310[16]; - uint8_t key3310_length; - uint8_t cwekey[17][16]; - uint8_t cwekey_length[17]; - uint8_t idird[4]; - uint8_t idird_length; - uint8_t kdt05_00[216]; - uint8_t kdt05_10[208]; - uint8_t edata[255]; - uint8_t dt5num; - uint8_t out[255]; - uint8_t ideakey1[16]; - uint8_t block3[8]; - uint8_t v[8]; - uint8_t iout[8]; - uint32_t dword_83DBC; - uint8_t data2[4]; - uint8_t ecmheader[4]; - uint8_t timestmp1[4]; - uint8_t timestmp2[4]; - uint8_t cak7expo[0x11]; - uint8_t data[0x80]; - uint8_t step1[0x60]; - uint8_t step2[0x68]; - uint8_t step3[0x6c]; - uint8_t encrypted[0x68]; - uint8_t result[104]; - uint8_t stillencrypted[0x50]; - uint8_t resultrsa[0x50]; - uint32_t cak7_seq; - uint32_t needrestart; - uint8_t otpcsc[2]; - uint8_t otpcsc_length; - uint8_t otacsc[2]; - uint8_t otacsc_length; - uint8_t forcepair[1]; - uint8_t forcepair_length; - uint8_t cak7_camstate; - uint8_t cak7_aes_key[32]; - uint8_t cak7_aes_iv[16]; - int8_t forcecwswap; - int8_t evensa; - int8_t forceemmg; - int8_t cwpkota; - int8_t headermode; - struct timeb last_refresh; -#endif -#if defined(READER_DGCRYPT) || defined(READER_NAGRA_MERLIN) - uint8_t cardid[8]; -#endif -#ifdef CS_CACHEEX - CECSP cacheex; // CacheEx Settings - uint8_t cxnodeid_last[9]; // save previous nodeid - uint8_t cxnodeid_changer_detected; // save node-changer detection status -#endif - int32_t typ; - char label[64]; -#ifdef WEBIF - char *description; -#endif - char device[128]; -#ifdef WITH_CARDREADER - uint16_t slot; // in case of multiple slots like sc8in1; first slot = 1 - int32_t handle; // device handle - int64_t handle_nr; // device handle_nr for mutiple readers same driver - int32_t fdmc; // device handle for multicam - int32_t detect; - int32_t mhz; // actual clock rate of reader in 10khz steps - int32_t cardmhz; // standard clock speed your card should have in 10khz steps; normally 357 but for Irdeto cards 600 - int32_t divider; // PLL divider for internal readers -#endif - int32_t r_port; - char r_usr[64]; - char r_pwd[64]; // Max length 63 + null terminator - int32_t l_port; - CAIDTAB ctab; - uint32_t boxid; -#ifdef READER_TONGFANG - uint32_t tongfang_version; - uint8_t tongfang3_commkey[8]; - uint32_t tongfang3_calibsn; - uint32_t tongfang_boxid; - uint8_t tongfang3_deskey[8]; - uint8_t tongfang3_deskey_length; - uint8_t stbid[8]; - uint8_t stbid_length; -#endif -#ifdef READER_NAGRA_MERLIN - int8_t cak7_mode; - uint8_t cak7type; - uint8_t cwpkcaid[2]; - uint8_t cwpkcaid_length; - uint8_t nuid[4]; - uint8_t nuid_length; -#endif -#ifdef READER_NAGRA - int8_t nagra_read; // read nagra ncmed records: 0 Disabled (default), 1 read all records, 2 read valid records only - int8_t detect_seca_nagra_tunneled_card; -#endif -#ifdef READER_IRDETO - int8_t force_irdeto; -#endif -#ifdef WITH_CARDREADER - uint8_t boxkey[16]; // n3 boxkey 8 bytes, seca sessionkey 16 bytes, viaccess camid 4 bytes - uint8_t boxkey_length; - uint8_t rsa_mod[120]; // rsa modulus for nagra cards. - uint8_t rsa_mod_length; - uint8_t cwpk_mod[16]; // cwpk modulus for conax cards. - uint8_t cwpk_mod_length; - uint8_t des_key[128]; // 3des key for Viaccess 16 bytes, des key for Dre 128 bytes - uint8_t des_key_length; -#endif - uint8_t card_atr[64]; // ATR readed from card - int8_t card_atr_length; // length of ATR -#ifdef WITH_CARDREADER - uint8_t atr[64]; - int32_t atrlen; - int8_t seca_nagra_card; // seca nagra card -#endif - SIDTABS sidtabs; - SIDTABS lb_sidtabs; - uint8_t hexserial[8]; - int32_t nprov; - uint8_t prid[CS_MAXPROV][8]; - uint8_t sa[CS_MAXPROV][4]; // viaccess & seca -#if defined(READER_NAGRA) || defined(READER_NAGRA_MERLIN) - int32_t nsa; - int32_t nemm82u; - int32_t nemm84; - int32_t nemm84s; - int32_t nemm83u; - int32_t nemm83s; - int32_t nemm87; - uint8_t emm82u[CS_MAXPROV][7]; - uint8_t emm84[CS_MAXPROV][3]; - uint8_t emm84s[CS_MAXPROV][6]; - uint8_t emm83; - uint8_t emm83u[CS_MAXPROV][6]; - uint8_t emm83s[CS_MAXPROV][6]; - uint8_t emm87[CS_MAXPROV][6]; - uint8_t emm82; -#endif - uint8_t read_old_classes; // viaccess - uint8_t maturity; // viaccess & seca maturity level - uint16_t caid; - uint16_t cak7_emm_caid; - uint16_t b_nano; - uint16_t s_nano; - int8_t ecmcommand; // used for filtering nagra bad ecm commands - uint8_t ecmcommandcache[5]; // cachebuff for ecm commands - int32_t blockemm; - int32_t saveemm; - LLIST *blockemmbylen; - char *emmfile; - char pincode[5]; - int8_t logemm; - int8_t cachemm; - int16_t rewritemm; - int16_t deviceemm; // catch device specific emms (so far only used for viaccess) - int8_t card_status; -#ifdef WITH_CARDREADER - int8_t deprecated; // if 0 ATR obeyed, if 1 default speed (9600) is chosen; for devices that cannot switch baudrate -#endif - int8_t resetalways; // send reset after each commands (for pscs) - struct s_module ph; - const struct s_cardreader *crdr; - void *crdr_data; // Private card reader data - bool crdr_flush; // sci readers may disable flush per reader - const struct s_cardsystem *csystem; - void *csystem_data; // Private card system data - bool csystem_active; - uint8_t ncd_key[14]; - uint8_t ncd_skey[16]; - int8_t ncd_connect_on_init; - int8_t ncd_disable_server_filt; - int8_t ncd_proto; - int8_t currenthops; // number of hops (cccam & gbox) -#ifdef MODULE_CCCAM - char cc_version[7]; // cccam version - char cc_build[7]; // cccam build number - int8_t cc_maxhops; // cccam max distance - int8_t cc_mindown; // cccam min downhops - int8_t cc_want_emu; // Schlocke: Client want to have EMUs, 0 - NO; 1 - YES - uint32_t cc_id; - int8_t cc_keepalive; - int8_t cc_hop; // For non-cccam reader: hop for virtual cards - int8_t cc_reshare; - int32_t cc_reconnect; // reconnect on ecm-request timeout -#endif - int8_t tcp_connected; - int32_t tcp_ito; // inactivity timeout - int32_t tcp_rto; // reconnect timeout - int32_t tcp_reconnect_delay; // max tcp connection block delay - uint8_t ipv4force; - uint8_t ipv6_connect_failed; - struct timeb tcp_block_connect_till; // time tcp connect ist blocked - int32_t tcp_block_delay; // incrementing block time - time_t last_g; // get (if last_s-last_g>tcp_rto - reconnect ) - time_t last_s; // send - time_t last_check; // last checked - time_t last_poll; // last poll - FTAB fchid; - FTAB ftab; - CLASSTAB cltab; - ECM_WHITELIST ecm_whitelist; - ECM_HDR_WHITELIST ecm_hdr_whitelist; - int32_t brk_pos; - int32_t msg_idx; - int32_t secatype; // 0=not determined, 2=seca2, 3=nagra(~seca3) this is only valid for localreaders! - uint32_t maxreadtimeout; // in us - uint32_t minreadtimeout; // in us - uint32_t maxwritetimeout; // in us - uint32_t minwritetimeout; // in us -#if defined(WEBIF) || defined(LCDSUPPORT) - int32_t emmwritten[4]; // count written EMM - int32_t emmskipped[4]; // count skipped EMM - int32_t emmerror[4]; // count error EMM - int32_t emmblocked[4]; // count blocked EMM - int32_t webif_emmwritten[4]; // count written EMM for webif reader info - int32_t webif_emmskipped[4]; // count skipped EMM for webif reader info - int32_t webif_emmerror[4]; // count error EMM for reader webif info - int32_t webif_emmblocked[4]; // count blocked EMM for reader webif info - int32_t lbvalue; // loadbalance Value -#endif -#ifdef WITH_AZBOX - int32_t azbox_mode; -#endif -#ifdef WITH_CARDREADER - int32_t use_gpio; // Should this reader use GPIO functions - int gpio_outen; // fd of opened /dev/gpio/outen - int gpio_out; // fd of opened /dev/gpio/out - int gpio_in; // fd of opened /dev/gpio/in - uint32_t gpio; // gpio addr - // variables from icc_async.h start - int32_t convention; // Convention of this ICC - uint8_t protocol_type; // Type of protocol - uint32_t current_baudrate; // (for overclocking uncorrected) baudrate to prevent unnecessary conversions from/to termios structure - double worketu; // in us for internal and external readers calculated (1/D)*(F/cardclock)*1000000 - uint32_t read_timeout; // Max timeout (ETU) to receive characters - uint32_t char_delay; // Delay (ETU) after transmiting each successive char - uint32_t block_delay; // Delay (ms) after starting to transmit - uint32_t BWT, CWT; // (for overclocking uncorrected) block waiting time, character waiting time, in ETU - // variables from io_serial.h - int32_t written; // keep score of how much bytes are written to serial port, since they are echoed back they have to be read - // variables from protocol_t1.h - uint16_t ifsc; // Information field size for the ICC - uint8_t ns; // Send sequence number - int16_t smartdev_found; - int16_t smart_type; - uint16_t statuscnt; - uint16_t modemstat; -#endif -#ifdef READER_CRYPTOWORKS - EMM_PACKET *last_g_emm; // last global EMM - bool last_g_emm_valid; // status of last global EMM -#endif - uint8_t rom[15]; - uint8_t irdId[4]; -#ifdef READER_VIDEOGUARD - uint8_t payload4C[15]; - uint16_t VgCredit; - uint16_t VgPin; - uint8_t VgFuse; - uint8_t VgCountryC[3]; - uint8_t VgRegionC[8]; - uint8_t VgLastPayload[6]; - int32_t card_startdate_basemonth; - int32_t card_startdate_baseyear; - int32_t card_expiredate_basemonth; - int32_t card_expiredate_baseyear; -#endif -#ifdef WITH_LB - int32_t lb_weight; // loadbalance weight factor, if unset, weight=100. The higher the value, the higher the usage-possibility - int8_t lb_force_fallback; // force this reader as fallback if fallback or fallback_percaid paramters set - int32_t lb_usagelevel; // usagelevel for loadbalancer - int32_t lb_usagelevel_ecmcount; - struct timeb lb_usagelevel_time; // time for counting ecms, this creates usagelevel - struct timeb lb_last; // time for oldest reader - LLIST *lb_stat; // loadbalancer reader statistics - CS_MUTEX_LOCK lb_stat_lock; - int32_t lb_stat_busy; // do not add while saving -#endif - time_t card_valid_to; - // ratelimit - int32_t ratelimitecm; - int32_t ratelimittime; // ratelimit time in ms (everything below 60 ms is converted to ms by applying *1000) - int8_t ecmunique; // check for matching ecm hash in ratelimitslot - int32_t srvidholdtime; // time in ms to keep srvid in ratelimitslot (during this time not checked for ecmunique!) - // (everything below 60 ms is converted to ms by applying *1000) - struct timeb lastdvbapirateoverride; - uint32_t ecmsok; -#ifdef CS_CACHEEX_AIO - uint32_t ecmsoklg; -#endif - uint32_t webif_ecmsok; - uint32_t ecmsnok; - uint32_t webif_ecmsnok; - uint32_t ecmstout; - uint32_t webif_ecmstout; - uint32_t ecmnotfoundlimit; // config setting. restart reader if ecmsnok >= ecmnotfoundlimit - int32_t ecmsfilteredhead; // count filtered ECM's by ECM Headerwhitelist - int32_t ecmsfilteredlen; // count filtered ECM's by ECM Whitelist - int32_t webif_ecmsfilteredhead; // count filtered ECM's by ECM Headerwhitelist to readers ecminfo - int32_t webif_ecmsfilteredlen; // count filtered ECM's by ECM Whitelist to readers ecm info - float ecmshealthok; -#ifdef CS_CACHEEX_AIO - float ecmshealthoklg; -#endif - float ecmshealthnok; - float ecmshealthtout; - int32_t cooldown[2]; - int32_t maxparallel; // max parallel active services, 0 = unlimited (default) - float parallelfactor; // zapping tolerance multiplier (default: 2.0) - int32_t paralleltimeout; // timeout buffer in ms after expected ECM (default: 1000) - struct s_parallel_slot *parallel_slots; // regular service tracking (size: maxparallel) - struct s_parallel_slot *parallel_slots_prov; // pending service tracking (size: maxparallel * parallelfactor, rounded) - LLIST *blocked_services; // list of s_blocked_client for dropped services - CS_MUTEX_LOCK parallel_lock; // lock for parallel_slots access - int8_t parallel_full; // flag: 1 if reader is at capacity limit - int8_t cooldownstate; - struct timeb cooldowntime; - struct ecmrl rlecmh[MAXECMRATELIMIT]; -#ifdef READER_VIDEOGUARD - int8_t ndsversion; // 0 auto (default), 1 NDS1, 12 NDS1+, 2 NDS2 - int8_t fix_07; - int8_t fix_9993; - int8_t readtiers; // method to get videoguard tiers - uint8_t ins7E[0x1A + 1]; - uint8_t ins7E11[0x01 + 1]; - uint8_t ins42[0x25 + 1]; - uint8_t ins2e06[0x04 + 1]; - uint8_t k1_generic[0x10 + 1]; // k1 for generic pairing mode - uint8_t k1_unique[0x10 + 1]; // k1 for unique pairing mode -#endif -#ifdef WITH_CARDREADER - int8_t smargopatch; - int8_t autospeed; // 1 clockspeed set according to atr f max - int8_t ins7e11_fast_reset; - uint8_t sc8in1_dtrrts_patch; // fix for kernel commit 6a1a82df91fa0eb1cc76069a9efe5714d087eccd -#endif - -#ifdef READER_VIACCESS - AES_ENTRY *aes_list; // multi AES linked list - uint8_t initCA28; // To set when CA28 succeed - uint32_t key_schedule1[32]; - uint32_t key_schedule2[32]; -#endif - -#if defined(READER_DRE) || defined(READER_DRECAS) - char *userscript; - uint32_t force_ua; -#endif - -#ifdef READER_DRECAS - char *stmkeys; -#endif - -#ifdef MODULE_GBOX - uint8_t gbox_maxdist; - uint8_t gbox_maxecmsend; - uint8_t gbox_reshare; - int8_t gbox_cccam_reshare; - char last_gsms[128]; - uint16_t gbox_remm_peer; - uint16_t gbox_gsms_peer; - uint8_t gbox_force_remm; - uint16_t gbox_cw_src_peer; - uint8_t gbox_crd_slot_lev; - FTAB ccc_gbx_reshare_ident; - uint8_t send_offline_cmd; - uint16_t nb_send_crds; -#endif - -#ifdef MODULE_PANDORA - uint8_t pand_send_ecm; -#endif -#ifdef MODULE_GHTTP - uint8_t ghttp_use_ssl; -#endif -#ifdef WITH_EMU - FTAB emu_auproviders; // AU providers for Emu reader - int8_t emu_datecodedenabled; // date-coded keys for BISS - LLIST *ll_biss2_rsa_keys; // BISS2 RSA keys - Read from external PEM files -#endif -#ifdef READER_CONAX - uint8_t cnxlastecm; // == 0 - last ecm has not been paired ecm, > 0 last ecm has been paired ecm -#endif - LLIST *emmstat; // emm stats - CS_MUTEX_LOCK emmstat_lock; - struct s_reader *next; -}; - -struct s_cpmap -{ - uint16_t caid; - uint32_t provid; - uint16_t sid; - uint16_t chid; - uint16_t dwtime; - struct s_cpmap *next; -}; - -struct s_auth -{ - char usr[64]; - char *pwd; -#ifdef WEBIF - char *description; -#endif - int8_t uniq; -#ifdef CS_CACHEEX - CECSP cacheex; // CacheEx Settings - uint8_t no_wait_time; - uint8_t disablecrccacheex; - FTAB disablecrccacheex_only_for; -#endif - int16_t allowedprotocols; - LLIST *aureader_list; - int8_t autoau; - uint8_t emm_reassembly; // 0 = OFF; 1 = OFF / DVBAPI = ON; 2 = ON (default) - int8_t monlvl; - uint64_t grp; - int32_t tosleep; - int32_t umaxidle; - CAIDTAB ctab; - SIDTABS sidtabs; - FTAB fchid; - FTAB ftab; // user [caid] and ident filter - CLASSTAB cltab; - TUNTAB ttab; - int8_t preferlocalcards; - uint32_t max_connections; -#ifdef CS_ANTICASC - int32_t ac_fakedelay; // When this is -1, the global ac_fakedelay is used - int32_t ac_users; // 0 - unlimited - int8_t ac_penalty; // 0 - log, >0 - fake dw - struct s_acasc ac_stat; - int8_t acosc_max_ecms_per_minute; // user value 0 - unlimited - int8_t acosc_max_active_sids; // user value 0 - unlimited - int8_t acosc_zap_limit; // user value 0 - unlimited - int8_t acosc_penalty; // user value penalty - int32_t acosc_penalty_duration; // user value how long is penalty activ in sek. - time_t acosc_penalty_until; - int8_t acosc_penalty_active; // 0-deaktiv 1-max_active_sids 2-zap_limit 3-max_ecms_per_minute 4-penaly_duration - int32_t acosc_delay; // user value - int8_t acosc_user_zap_count; - time_t acosc_user_zap_count_start_time; -#endif -#ifdef WITH_LB - int32_t lb_nbest_readers; // When this is -1, the global lb_nbest_readers is used - int32_t lb_nfb_readers; // When this is -1, the global lb_nfb_readers is used - CAIDVALUETAB lb_nbest_readers_tab; // like nbest_readers, but for special caids -#endif - IN_ADDR_T dynip; - char *dyndns; - time_t expirationdate; - time_t firstlogin; - uint32_t allowedtimeframe[SIZE_SHORTDAY][24][2]; // day[0-sun to 6-sat, 7-ALL],hours,minutes use as binary flags to reduce mem usage - uint8_t allowedtimeframe_set; // flag for internal use to mention if allowed time frame is used - int8_t c35_suppresscmd08; - uint8_t c35_sleepsend; - int8_t ncd_keepalive; -#ifdef MODULE_CCCAM - int32_t cccmaxhops; - int8_t cccreshare; - int8_t cccignorereshare; - int8_t cccstealth; -#endif - int8_t disabled; - int32_t failban; - - int32_t cwfound; - int32_t cwcache; - int32_t cwnot; - int32_t cwtun; - int32_t cwignored; - int32_t cwtout; -#ifdef CW_CYCLE_CHECK - int32_t cwcycledchecked; // count checked cwcycles per client - int32_t cwcycledok; // count pos checked cwcycles per client - int32_t cwcyclednok; // count neg checked cwcycles per client - int32_t cwcycledign; // count ign cwcycles per client - int8_t cwc_disable; // disable cwc checking for this Client -#endif - int32_t emmok; - int32_t emmnok; -#ifdef CS_CACHEEX - int32_t cwcacheexpush; // count pushed ecms/cws - int32_t cwcacheexgot; // count got ecms/cws - int32_t cwcacheexhit; // count hit ecms/cws - int32_t cwcacheexerr; // cw=00 or chksum wrong - int32_t cwcacheexerrcw; // Same Hex, different CW - int32_t cwc_info; // count of in/out comming cacheex ecms with CWCinfo -#ifdef CS_CACHEEX_AIO - int32_t cwcacheexgotlg; // count got localgenerated-flagged CWs - int32_t cwcacheexpushlg; // count pushed localgenerated-flagged CWs -#endif -#endif - struct s_auth *next; -}; - - -struct s_srvid_caid -{ - uint16_t caid; - uint16_t nprovid; - uint32_t *provid; -}; - -struct s_srvid -{ - uint16_t srvid; - int8_t ncaid; - struct s_srvid_caid *caid; - char *data; - const char *prov; - const char *name; - const char *type; - const char *desc; - struct s_srvid *next; -}; - -struct s_rlimit -{ - struct ecmrl rl; - struct s_rlimit *next; -}; - -struct s_cw -{ - uint8_t cw[16]; -}; - -struct s_fakecws -{ - uint32_t count; - struct s_cw *data; -}; - -#ifdef MODULE_SERIAL -struct s_twin -{ - struct ecmtw tw; - struct s_twin *next; -}; -#endif - -struct s_tierid -{ - uint16_t tierid; - int8_t ncaid; - uint16_t caid[10]; - char name[33]; - struct s_tierid *next; -}; - -struct s_provid -{ - uint16_t caid; - uint16_t nprovid; - uint32_t *provid; - char prov[33]; - char sat[33]; - char lang[33]; - struct s_provid *next; -}; - -struct s_ip -{ - IN_ADDR_T ip[2]; - struct s_ip *next; -}; - -struct s_global_whitelist -{ - uint32_t line; // linenr of oscam.whitelist file, starting with 1 - char type; // w or i or l - uint16_t caid; - uint32_t provid; - uint16_t srvid; - uint16_t chid; - uint16_t pid; - uint16_t ecmlen; - uint16_t mapcaid; - uint32_t mapprovid; - struct s_global_whitelist *next; -}; - -struct s_cacheex_matcher -{ - uint32_t line; // linenr of oscam.Cacheex file, starting with 1 - char type; // m - uint16_t caid; - uint32_t provid; - uint16_t srvid; - uint16_t chid; - uint16_t pid; - uint16_t ecmlen; - - uint16_t to_caid; - uint32_t to_provid; - uint16_t to_srvid; - uint16_t to_chid; - uint16_t to_pid; - uint16_t to_ecmlen; - - int32_t valid_from; - int32_t valid_to; - - struct s_cacheex_matcher *next; -}; - -struct s_config -{ - int32_t nice; - uint32_t netprio; - uint32_t ctimeout; - uint32_t ftimeout; - CAIDVALUETAB ftimeouttab; - CAIDVALUETAB ctimeouttab; // ← clienttimeout_percaid - uint32_t cmaxidle; - int32_t ulparent; - uint32_t delay; - int32_t bindwait; - int32_t tosleep; - IN_ADDR_T srvip; - char *usrfile; - char *cwlogdir; - char *emmlogdir; - char *logfile; - char *mailfile; - int8_t disablecrccws; // 1=disable cw checksum test. 0=enable checksum check - FTAB disablecrccws_only_for; // ignore checksum for selected caid provid -#ifdef CS_CACHEEX_AIO - uint8_t cacheex_srcname_webif; // show cacheex-srcname not cache3 in log -#endif - uint8_t logtostdout; - uint8_t logtosyslog; - int8_t logduplicatelines; - int32_t initial_debuglevel; - char *sysloghost; - int32_t syslogport; -#if defined(WEBIF) || defined(MODULE_MONITOR) - uint32_t loghistorylines; -#endif - int8_t disablelog; - int8_t disablemail; - int8_t disableuserfile; - int8_t usrfileflag; - struct s_auth *account; - struct s_srvid *srvid[16]; - struct s_tierid *tierid; - struct s_provid *provid; - struct s_sidtab *sidtab; -#ifdef MODULE_MONITOR - int32_t mon_port; - IN_ADDR_T mon_srvip; - struct s_ip *mon_allowed; - uint8_t mon_level; -#endif - int32_t aulow; - int32_t hideclient_to; -#ifdef WEBIF - int32_t http_port; - IN_ADDR_T http_srvip; - char *http_user; - char *http_pwd; - char *http_css; - int8_t http_prepend_embedded_css; - char *http_jscript; - char *http_tpl; - char *http_piconpath; - char *http_script; -#ifndef WEBIF_JQUERY - char *http_extern_jquery; -#endif - int32_t http_refresh; - int32_t poll_refresh; - int8_t http_hide_idle_clients; - char *http_hide_type; - int8_t http_showpicons; - int8_t http_picon_size; - int8_t http_status_log; - int8_t http_showmeminfo; - int8_t http_showecminfo; - int8_t http_showloadinfo; - int8_t http_showuserinfo; - int8_t http_showreaderinfo; - int8_t http_showcacheexinfo; - struct s_ip *http_allowed; - int8_t http_readonly; - IN_ADDR_T http_dynip[MAX_HTTP_DYNDNS]; - uint8_t http_dyndns[MAX_HTTP_DYNDNS][64]; - int8_t http_use_ssl; - int8_t https_force_secure_mode; - int8_t https_auto_create_cert; - char *http_cert; - char *http_help_lang; - char *http_locale; - char *http_oscam_label; - int32_t http_emmu_clean; - int32_t http_emms_clean; - int32_t http_emmg_clean; -#endif - int8_t http_full_cfg; - int8_t http_overwrite_bak_file; - int32_t failbantime; - int32_t failbancount; - LLIST *v_list; // Failban list -#ifdef MODULE_CAMD33 - int32_t c33_port; - IN_ADDR_T c33_srvip; - uint8_t c33_key[16]; - int32_t c33_crypted; - int32_t c33_passive; - struct s_ip *c33_plain; -#endif -#if defined(MODULE_CAMD35) || defined(MODULE_CAMD35_TCP) - int32_t c35_port; - IN_ADDR_T c35_srvip; - int8_t c35_tcp_suppresscmd08; - int8_t c35_udp_suppresscmd08; - PTAB c35_tcp_ptab; - IN_ADDR_T c35_tcp_srvip; -#endif - int8_t c35_suppresscmd08; // used in cccam module - int8_t getblockemmauprovid; - int32_t umaxidle; //User max Idle -#ifdef MODULE_NEWCAMD - PTAB ncd_ptab; - IN_ADDR_T ncd_srvip; - uint8_t ncd_key[14]; - int8_t ncd_keepalive; - int8_t ncd_mgclient; - struct s_ip *ncd_allowed; -#endif -#ifdef MODULE_RADEGAST - int32_t rad_port; - IN_ADDR_T rad_srvip; - struct s_ip *rad_allowed; - char *rad_usr; -#endif -#ifdef MODULE_CCCAM - uint16_t cc_port[CS_MAXPORTS]; - int8_t cc_reshare; - int8_t cc_ignore_reshare; - int32_t cc_update_interval; - IN_ADDR_T cc_srvip; - char cc_version[7]; - int8_t cc_minimize_cards; - int8_t cc_keep_connected; - int8_t cc_stealth; - int8_t cc_reshare_services; - int8_t cc_forward_origin_card; - uint8_t cc_fixed_nodeid[8]; - uint32_t cc_recv_timeout; // The poll() timeout parameter in ms. Default: DEFAULT_CC_RECV_TIMEOUT (2000 ms). -#endif -#ifdef MODULE_GBOX - #define GBOX_MY_VERS_DEF 0x2A - #define GBOX_MY_CPU_API_DEF 0x61 - #define GBOX_MAX_PROXY_CARDS 32 - #define GBOX_MAX_IGNORED_PEERS 16 - #define GBOX_MAX_BLOCKED_ECM 16 - #define GBOX_MAX_REMM_PEERS 8 - #define GBOX_MAX_DEST_PEERS 16 - #define GBOX_MAX_MSG_TXT 127 - uint16_t gbox_port[CS_MAXPORTS]; - char *gbox_hostname; - uint32_t gbox_reconnect; - uint32_t gbox_password; - unsigned long gbox_proxy_card[GBOX_MAX_PROXY_CARDS]; - int8_t gbox_proxy_cards_num; - uint32_t gbox_my_vers; - uint8_t gbox_my_cpu_api; - uint8_t gsms_dis; - uint8_t log_hello; - uint8_t dis_attack_txt; - char *gbox_tmp_dir; - uint8_t cc_gbx_reshare_en; - uint16_t gbox_ignored_peer[GBOX_MAX_IGNORED_PEERS]; - uint8_t gbox_ignored_peer_num; - uint16_t accept_remm_peer[GBOX_MAX_REMM_PEERS]; - uint8_t accept_remm_peer_num; - uint16_t gbox_block_ecm[GBOX_MAX_BLOCKED_ECM]; - uint8_t gbox_block_ecm_num; - uint8_t gbox_save_gsms; - uint8_t gbox_msg_type; - uint16_t gbox_dest_peers[GBOX_MAX_DEST_PEERS]; - uint8_t gbox_dest_peers_num; - char gbox_msg_txt[GBOX_MAX_MSG_TXT+1]; -#endif -#ifdef MODULE_SERIAL - char *ser_device; -#endif - int32_t max_log_size; - int8_t waitforcards; - int32_t waitforcards_extra_delay; - int8_t preferlocalcards; - int32_t reader_restart_seconds; // schlocke: reader restart auf x seconds, disable = 0 - int8_t dropdups; // drop duplicate logins - - - // Loadbalancer-Config: - int32_t lb_mode; // schlocke: reader loadbalancing mode - int32_t lb_auto_betatunnel; // automatic selection of betatunnel convertion based on learned data - int32_t lb_auto_betatunnel_mode; // automatic selection of betatunnel direction -#ifdef WITH_LB - int32_t lb_save; // schlocke: load/save statistics to file, save every x ecms - int32_t lb_nbest_readers; // count of best readers - int32_t lb_nfb_readers; // count of fallback readers - int32_t lb_min_ecmcount; // minimal ecm count to evaluate lbvalues - int32_t lb_max_ecmcount; // maximum ecm count before reseting lbvalues - int32_t lb_reopen_seconds; // time between retrying failed readers/caids/prov/srv - int8_t lb_reopen_invalid; // default=1; if 0, rc=E_INVALID will be blocked until stats cleaned - int8_t lb_force_reopen_always; // force reopening immediately all failing readers if no matching reader found - int32_t lb_retrylimit; // reopen only happens if reader response time > retrylimit - CAIDVALUETAB lb_retrylimittab; - CAIDVALUETAB lb_nbest_readers_tab; // like nbest_readers, but for special caids - CAIDTAB lb_noproviderforcaid; // do not store loadbalancer stats with providers for this caid - char *lb_savepath; // path where the stat file is save. Empty=default=/tmp/.oscam/stat - int32_t lb_stat_cleanup; // duration in hours for cleaning old statistics - int32_t lb_max_readers; // limit the amount of readers during learning - int32_t lb_auto_betatunnel_prefer_beta; // prefer-beta-over-nagra factor - int32_t lb_auto_timeout; // Automatic timeout by loadbalancer statistics - int32_t lb_auto_timeout_p; // percent added to avg time as timeout time - int32_t lb_auto_timeout_t; // minimal time added to avg time as timeout time -#endif - int32_t resolve_gethostbyname; - int8_t double_check; // schlocke: Double checks each ecm+dcw from two (or more) readers - FTAB double_check_caid; // do not store loadbalancer stats with providers for this caid - - // CW Vote settings - int8_t cwvote_enabled; - int8_t cwvote_log_enabled; - int32_t cwvote_timeout; // w milisekundach, 0 = wyłączony - int32_t cwvote_min_votes; - float cwvote_local_weight; // waga local readera (np. 2.0) - int32_t cwvote_max_candidates; - int32_t cwvote_compare_len; // 8 lub 16 - int32_t cwvote_fallback; // 0=wait, 1=best anyway, 2=first CW - CW_VOTE_CAID_TAB cwvote_caids; - -#ifdef HAVE_DVBAPI - int8_t dvbapi_enabled; - int8_t dvbapi_au; - char *dvbapi_usr; - int8_t dvbapi_boxtype; - int8_t dvbapi_pmtmode; - int8_t dvbapi_requestmode; - int32_t dvbapi_listenport; // TCP port to listen instead of camd.socket (network mode, default=0 -> disabled) - IN_ADDR_T dvbapi_srvip; - SIDTABS dvbapi_sidtabs; - int32_t dvbapi_delayer; // delayer ms, minimum time to write cw - int8_t dvbapi_ecminfo_file; // Enable or disable ecm.info file creation - int8_t dvbapi_ecminfo_type; - int8_t dvbapi_read_sdt; - int8_t dvbapi_write_sdt_prov; - int8_t dvbapi_extended_cw_api; -#ifdef MODULE_STREAMRELAY - int8_t dvbapi_demuxer_fix; -#endif -#endif - -#ifdef CS_ANTICASC - int8_t ac_enabled; - int32_t ac_users; // num of users for account (0 - default) - int32_t ac_stime; // time to collect AC statistics (3 min - default) - int32_t ac_samples; // qty of samples - int8_t ac_penalty; // 0 - write to log - int32_t ac_fakedelay; // 100-1000 ms - int32_t ac_denysamples; - char *ac_logfile; - struct s_cpmap *cpmap; - int8_t acosc_enabled; - int8_t acosc_max_ecms_per_minute; // global value 0 - unlimited - int8_t acosc_max_active_sids; // global value 0 - unlimited - int8_t acosc_zap_limit; // global value 0 - unlimited - int32_t acosc_penalty_duration; // global value how long is penalty activ in sek. - int8_t acosc_penalty; // global value - int32_t acosc_delay; // global value -#endif - -#ifdef LEDSUPPORT - int8_t enableled; // 0=disabled led, 1=enable led for routers, 2=enable qboxhd led -#endif - -#ifdef LCDSUPPORT - int8_t enablelcd; - char *lcd_output_path; - int32_t lcd_hide_idle; - int32_t lcd_write_intervall; -#endif - -#ifdef MODULE_PANDORA - int8_t pand_skip_send_dw; - struct s_ip *pand_allowed; - char *pand_usr; - char *pand_pass; - int8_t pand_ecm; - int32_t pand_port; - IN_ADDR_T pand_srvip; -#endif - -#ifdef MODULE_SCAM - int32_t scam_port; - IN_ADDR_T scam_srvip; - struct s_ip *scam_allowed; -#endif - -#ifdef MODULE_STREAMRELAY - int8_t stream_relay_enabled; - int32_t stream_relay_port; - char *stream_relay_user; - CAIDTAB stream_relay_ctab; // use the stream server for these caids - char *stream_source_host; - int8_t stream_client_source_host; - int32_t stream_source_port; - char *stream_source_auth_user; - char *stream_source_auth_password; - uint32_t stream_relay_buffer_time; - int8_t stream_relay_reconnect_count; - int8_t stream_display_client; - int8_t stream_reuse_client; -#ifdef WEBIF - int8_t stream_hide_client; -#endif -#ifdef WITH_NEUTRINO -#define DEFAULT_STREAM_SOURCE_PORT 31339 //Neutrino -#else -#define DEFAULT_STREAM_SOURCE_PORT 8001 //Enigma2 -#endif -#endif -#ifdef WITH_EMU - uint32_t emu_stream_ecm_delay; - int8_t emu_stream_emm_enabled; -#endif - - int32_t max_cache_time; // seconds ecms are stored in ecmcwcache - int32_t max_hitcache_time; // seconds hits are stored in cspec_hitcache (to detect dyn wait_time) - - int8_t reload_useraccounts; - int8_t reload_readers; - int8_t reload_provid; - int8_t reload_services_ids; - int8_t reload_tier_ids; - int8_t reload_fakecws; - int8_t reload_ac_stat; - int8_t reload_log; - - int8_t block_same_ip; // 0=allow all, 1=block client requests to reader with same ip (default=1) - int8_t block_same_name; // 0=allow all, 1=block client requests to reader with same name (default=1) - -#ifdef CS_CACHEEX -#ifdef CS_CACHEEX_AIO - uint32_t cw_cache_size; - uint32_t cw_cache_memory; - CWCHECKTAB cw_cache_settings; - - uint32_t ecm_cache_size; - uint32_t ecm_cache_memory; - int32_t ecm_cache_droptime; -#endif - uint8_t wait_until_ctimeout; - CWCHECKTAB cacheex_cwcheck_tab; - IN_ADDR_T csp_srvip; - int32_t csp_port; - CECSPVALUETAB cacheex_wait_timetab; - CAIDVALUETAB cacheex_mode1_delay_tab; -#ifdef CS_CACHEEX_AIO - uint8_t waittime_block_start; - uint16_t waittime_block_time; -#endif - CECSP csp; // CSP Settings - uint8_t cacheex_enable_stats; // enable stats - struct s_cacheex_matcher *cacheex_matcher; -#ifdef CS_CACHEEX_AIO - uint8_t cacheex_dropdiffs; - uint8_t cacheex_lg_only_remote_settings; - uint8_t cacheex_localgenerated_only; - CAIDTAB cacheex_localgenerated_only_caidtab; - FTAB lg_only_tab; - uint8_t localgenerated_only_in; - CAIDTAB localgenerated_only_in_caidtab; - FTAB lg_only_in_tab; - uint8_t lg_only_in_aio_only; - uint8_t lg_only_remote_settings; - int32_t feature_bitfield; - char aio_version[CS_AIO_VERSION_LEN]; -#endif - CAIDVALUETAB cacheex_nopushafter_tab; - uint8_t cacheex_localgenerated_only_in; - CAIDTAB cacheex_localgenerated_only_in_caidtab; - FTAB cacheex_lg_only_in_tab; - uint8_t cacheex_lg_only_in_aio_only; - CECSPVALUETAB cacheex_filter_caidtab; - CECSPVALUETAB cacheex_filter_caidtab_aio; - uint32_t cacheex_push_lg_groups; - FTAB cacheex_lg_only_tab; -#endif - -#ifdef CW_CYCLE_CHECK - int8_t cwcycle_check_enable; // on or off - CAIDTAB cwcycle_check_caidtab; // Caid for CW Cycle Check - int32_t keepcycletime; // how long stay the learned Cycletime in Memory - int32_t maxcyclelist; // max size of cwcyclelist - int8_t onbadcycle; // what to do on bad cwcycle - int8_t cwcycle_dropold; // what to do on old ecmd5/cw - int8_t cwcycle_sensitive; - int8_t cwcycle_allowbadfromffb; // allow Bad cycles from Fixed Fallbackreader - int8_t cwcycle_usecwcfromce; // Use CWC Info from Cacheex Sources for CWC Checking -#endif - - // Global whitelist: - struct s_global_whitelist *global_whitelist; - int8_t global_whitelist_use_l; - int8_t global_whitelist_use_m; - - char *ecmfmt; - char *pidfile; - - int32_t max_pending; - - // Ratelimit list - struct s_rlimit *ratelimit_list; - - // fake cws - struct s_fakecws fakecws[0x100]; - -#ifdef MODULE_SERIAL - struct s_twin *twin_list; -#endif -}; - -struct s_clientinit -{ - void *(*handler)(struct s_client *); - struct s_client *client; -}; - -struct s_clientmsg -{ - uint8_t msg[1024]; - int32_t len; - int32_t cmd; -}; - -typedef struct reader_stat_t -{ - int32_t rc; - uint16_t caid; - uint32_t prid; - uint16_t srvid; - uint32_t chid; - int16_t ecmlen; - - struct timeb last_received; - - int32_t ecm_count; - int32_t time_avg; - int32_t time_stat[LB_MAX_STAT_TIME]; - int32_t time_idx; - - int32_t fail_factor; -} READER_STAT; - -typedef struct cs_stat_query -{ - uint16_t caid; - uint32_t prid; - uint16_t srvid; - uint32_t chid; - int16_t ecmlen; -} STAT_QUERY; - -struct s_write_from_cache -{ - ECM_REQUEST *er_new; - ECM_REQUEST *er_cache; -}; - -/* =========================== - * global variables - * =========================== */ -extern pthread_key_t getclient; -extern struct s_client *first_client; -extern CS_MUTEX_LOCK config_lock; -extern CS_MUTEX_LOCK clientlist_lock; -extern CS_MUTEX_LOCK readerlist_lock; -extern struct s_reader *first_active_reader; // points to list of _active_ readers (enable = 1, deleted = 0) -extern LLIST *configured_readers; - -// These are used pretty much everywhere -extern struct s_config cfg; -extern uint16_t cs_dblevel; - -#include "oscam-log.h" -#include "oscam-log-reader.h" - -// Add here *only* funcs that are implemented in oscam.c and are called in other places -void cs_exit(int32_t sig); -void cs_exit_oscam(void); -void cs_restart_oscam(void); -int32_t cs_get_restartmode(void); - -void set_thread_name(const char *thread_name); -int32_t start_thread(char *nameroutine, void *startroutine, void *arg, pthread_t *pthread, int8_t detach, int8_t modify_stacksize); -int32_t start_thread_nolog(char *nameroutine, void *startroutine, void *arg, pthread_t *pthread, int8_t detach, int8_t modify_stacksize); -void kill_thread(struct s_client *cl); - -struct s_module *get_module(struct s_client *cl); -void module_reader_set(struct s_reader *rdr); - -// Until we find a better place for these (they are implemented in oscam-simples.h) -char *get_servicename(struct s_client *cl, uint16_t srvid, uint32_t provid, uint16_t caid, char *buf, uint32_t buflen); -char *get_servicename_or_null(struct s_client *cl, uint16_t srvid, uint32_t provid, uint16_t caid, char *buf, uint32_t buflen); -char *get_picon_servicename_or_null(struct s_client *cl, uint16_t srvid, uint32_t provid, uint16_t caid, char *buf, uint32_t buflen); -int32_t picon_servicename_remve_hd(char *buf, uint32_t buflen); -char *get_tiername(uint16_t tierid, uint16_t caid, char *buf); -char *get_tiername_defaultid(uint16_t tierid, uint16_t caid, char *buf); -char *get_provider(uint32_t provid, uint16_t caid, char *buf, uint32_t buflen); -char *get_providername(uint32_t provid, uint16_t caid, char *buf, uint32_t buflen); -char *get_providername_or_null(uint32_t provid, uint16_t caid, char *buf, uint32_t buflen); -void add_provider(uint16_t caid, uint32_t provid, const char *name, const char *sat, const char *lang); -const char *get_cl_lastprovidername(struct s_client *cl); -bool boxtype_is(const char *boxtype); -bool boxname_is(const char *boxname); -const char *boxtype_get(void); -const char *boxname_get(void); -static inline bool caid_is_fake(uint16_t caid) { return caid == 0xffff; } -static inline bool caid_is_biss(uint16_t caid) { return caid >> 8 == 0x26; } -static inline bool caid_is_biss_fixed(uint16_t caid) { return caid == 0x2600 || caid == 0x2602; } // fixed cw, fake ecm -static inline bool caid_is_biss_dynamic(uint16_t caid) { return caid == 0x2610; } // dynamic cw, real ecm and emm -static inline bool caid_is_seca(uint16_t caid) { return caid >> 8 == 0x01; } -static inline bool caid_is_viaccess(uint16_t caid) { return caid >> 8 == 0x05; } -static inline bool caid_is_irdeto(uint16_t caid) { return caid >> 8 == 0x06; } -static inline bool caid_is_videoguard(uint16_t caid) { return caid >> 8 == 0x09; } -static inline bool caid_is_conax(uint16_t caid) { return caid >> 8 == 0x0B; } -static inline bool caid_is_cryptoworks(uint16_t caid) { return caid >> 8 == 0x0D; } -static inline bool caid_is_powervu(uint16_t caid) { return caid >> 8 == 0x0E; } -static inline bool caid_is_director(uint16_t caid) { return caid >> 8 == 0x10; } -static inline bool caid_is_betacrypt(uint16_t caid) { return caid >> 8 == 0x17; } -static inline bool caid_is_nagra(uint16_t caid) { return caid >> 8 == 0x18; } -static inline bool caid_is_bulcrypt(uint16_t caid) { return caid == 0x5581 || caid == 0x4AEE; } -static inline bool caid_is_dre(uint16_t caid) { return caid == 0x4AE0 || caid == 0x4AE1 || caid == 0x2710;} -static inline bool caid_is_tongfang(uint16_t caid) { return caid == 0x4A02; } -#if defined(WITH_EXTENDED_CW) || defined(MODULE_STREAMRELAY) -static inline bool select_csa_alt(const ECM_REQUEST *er) { - return (caid_is_videoguard(er->caid) && er->ecm[4] != 0 && (er->ecm[2] - er->ecm[4]) == 4); -} -#endif -#ifdef MODULE_STREAMRELAY -static inline uint8_t get_ecm_mode(const ECM_REQUEST *er) { - return (caid_is_videoguard(er->caid) && er->ecmlen >= 4) ? (er->ecm[er->ecmlen - 1] & 0x0F) : 0; -} -#endif -const char *get_cardsystem_desc_by_caid(uint16_t caid); - -#ifdef WITH_EMU -FILTER *get_emu_prids_for_caid(struct s_reader *rdr, uint16_t caid); -#endif - -#endif diff --git a/images/image1.jpg b/images/image1.jpg deleted file mode 100755 index 0d27c94f904c5478a898c4847c1d4d415d6b9546..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73977 zcmeFa2Ut^Gmp>Yc(vjYzNbe$D0f~wWm+8O{N zA|ik{;UD019H0guAtwIuNBEEu{?3q}IYUZ%hLVizEIBnLH8m9_6%`FF104-5JuMX# z9Sa>jBNH<-Gxa%EHWnr}1}0{vA2%T)A^e8)48@r<6ihT!G)({L&*^6XJvmW4X)6g4 zAAp#ih=iW#v=zVu01%xa^!7)G|LsFWOz7iTGI9z^Dnf%wIsh>d2?;SN$&X$WTKg0J zA3#cfhJjc5`dLQ9dt`i%nPi^DWRUaUC~aak>PHL6-hUEALCM0(#?B!qBrGB-CMU0; zc=?Kw+D&y0O)c$P#&=9i&CD$iY1mtD}F+Ya(FC+Ws1{U;R8riP{`)yoE05u5_Ve&}m z0YJcsab~y(accP^7dhXRVUr{gfk(yf8JOO4n#IGKKi8iE(!`~{=;JRosI|hjrJU3D z)}-)(kY*8*yi-8%GoMp{swwDA8qS6X{ZR_I^rd?{?i3JFaz7lfatfHaYYXd*Ph1c_ z1+Z%3B&d21x65$Zr-0eDx0!)TFswOi+RlQ*q4p`Dt^X82MZAOeD?*3@v9*gL>9lEh zmNQGZLyG_-7{>h%U8xEG`Skz2l+S78wf$)Du;``Xv+b_6w5{Vo*zftsx{Zlw@D%WS z){Oo=BaKR{1KdvmzvsrR-*J-1SHo*uz~A%Y@*nxwjmdya{}0Rv{NMC=vv&dgJj~Dl zdYqDrjz&fGkc#dH+wm18`N%#Y<%q6%%J3!&Z39K=CNe7RI+#s+d@q5Re<|niI0=|D zRSoa~g({!(>y~WDk;nAF9z@5NhZLN!5O z#Cj*UtmLTX?62vlDG=(Ie#%L9p?DG<5(@KyUz}8)tC~!y`Zc| z(Nxkg!_#)cGshC_^#NREnH%k8=RV?fq*?>nw^|boB$X(&-AT$`*mb0VU^mlv`TM>;s*MW4cL>G*9 za5I#lvjh0+hvXt{1SGyD8fe^>wW`8N$izP(3Ax-(!S-MWK@%{^EikOg<7Yg&RdH1Y zxuhL*{uDr|&S@0$!LrvwutG}g@SWWv-xB!7lSgNOy0G5rLd%>6_*igd`5?4I=Ln>8 zu%~+XcYR8RIRV3`WUz+l=?Prv557W-Y~v{){ofZVS-pb9un%SprOxAx@=5&aF0Vz z(xSI>A?)t;Hm*}Z$tfT{<=A5^9=f(knBq16bMQat)jzJ!i#%-jv4At^wvq^iWV=}& z4j6bv%~~33r>m&%X!qVfbD9Mt>Gp|poAUj$_9tW;k$ICikAZq#hjeE%Zu(mEDPVuj z`@N-N?0pYyhB<-Agb&HX^LO==Zn)TFmseEJm~(3pSm`+{O)VZ359)QP9up|0uEwcF4JCDW?v-Z8(^KfIr+O}f4e9c zvHx6jerFB-QRDnva(@~ezZw7kr_C*YdUYlPqQ5xKdc8aa%-aqF*G51mfYBFb4UpGY zzeRjdW1|sB*yanm)+KgreizPr3V0!GPT1@?5oS_I3NIFTX}P!;d&498a6kGKKzyID zY5DN8%}@IL-^v?<(~w4oC20s{f;qe z)5`D`E;~&u@N5`*u9Y=zT+g+l8@j%{NosUfx?8ZI=-I7JcI)>HO44xZ3TV&*?st3n6rQ7-MlZbw4eDc-&b^HMw$E(zVJJvh}Jd=iD z?!cNEi(tJKFf1eMDS%nqX=?>*ae|bp>zQmYL6jgCPXXD*7|mCwfcqPcmRO4dEOGlO zK=TuNGk#WJ)KAngzsIfgo&!v&dATFh{JGY#t)kDdI%#l*OA3rn6 zZ!%Q!Vz6n(XKS$nndR&^8mF~Tb485q$yr)i&`pA6{`+od{;`j<6HwPG#Fy?}Q0grB z))c7t6wq@DXyIWR^E-<@nEBp#0Sj$8>S#IUq3}jn4oNK_YK|WwQ;HNdAxs8^^d8Y{ z#xZq3g)8Sbjuo+MGiMQbYoIfGFj|So45X7~YVs`B@%ZZJDpE~%IN3LWjxT1xO~P@n z{Gos5oIeWeogDkv6=;o6;xzK`h-q>hO6V3#GR_FbKYxy}=#`&q<#`DzPe}`r2Xd+v z;WVp;N3BE6>m5UoBM&^KsBgct-|n}6&FdhX-YjBbnR@jkqQs+@0mq)KKJ?I~0!CqJ z2}aH<(yk(dD=SKMIWonV@7r5YOqgwv^!UgBeb-FXx4VU>T)+EcPMulc-s5 zsSO~yyfuwgmD_wJfa%k~Mr9$_{a%yc%ETDS=+_JAcKHYMbAe<5>W?Ikm2o$*O|w)z zc5}3)GcUPOHyZopl7VDxkM0M<`K5c@`1RCSse&mlUwtCoJNieu`~!>M2rswU!j_m} zoj|g+{>4~jcq>+F=G;1ep|=966}^gt1-Y*!7ZY!3d>oMzkF>O^u}@`r+5IT4cm6}u zgbCetfK8po6P(pCt@m-eEf-qu=qu>l-Uh6tRtf7-aeN$UBzd)%?@D!w{j;n$-(+T< z5z($c`wZ`k{txVj{K-`ug6b5ot-mD*&cwr^+n~po_dMmSt0anHB7p^ThnF0`p^>Mdwj3o-V}>@1J!F`1}@uEdb6?i~yIAKpaKH zDIh%4cK>Ajc*|q?Fby^T%ojnMB-K0;P#Dj10n51WgUz~FJq-bIVblj$d2e%Ofr)0n~6fywaNnZG#breGZe_tU20c8P6mL@#zX?W7%V z(%na-{=}9VTRNlv((?#6b$&R}OqX)s257*7)@c--V|OqSqYiw&U3S(K&*1#64s-4X zx+A1W{={~1PImzQpt3s3Dp|BYRws<%vZ?tOXs8sQ=nnCQ@Z$K5k&!iM2NaR_XdHu6 zJg!X}10zk@PETi{NrIL0(_ z8b;%6iLdt9m*m%bR^nQsQWe)7sbNu-E)fvOc+I1Q)pW&+6T_^mWmd4Y4ok-ozyQ5u6Gf+j|7rr(MyE`BeZ|NH? zI{%$LC_0|VuAAudRVNJel{<_CY`AKjL|J@g}uRJV3XDNDbsgBy*&>V1*o#pqkjzwF6sLk=~ z!V4Y%w?Smxqqj<*#%kS7^R3sLXT)X~XSAIwRo`VcS`Pr7;9jd<#C_)rI%*Lo{(3TTBijN(2J9U3fepc?|89zTDD{n{k=+D)R-tL%Dg+-=w4PMP_~Uz|bC zsONFG`4a|hhK8{lhR48@0$gT;&A2LWni=L4&<;I|h1-UY8$NGKqxDk;h6I5zwfYx7 z&C}fSwT&{j(&Ty5666>_>j<@wEAI1+QRdvu z+JR@(S2HI|?T)9@*_8zSkJXirCwh;dNv8nuFDvf-*36kjRfC(RxQ9h3t7^Mx5cdk6 zb+q1NcFo_a9Y|X*olzW;>PK-gFI_c535>G8&Y48|8gz~2`lGTL7sH$>zE$d5szE3D z0t!6kMvZy!hB!4?`uUWn=2=zVFNf9-Cf>x~($Juq87i2gCMPwkH`K|r1)qF71^BM+ z){RyMXUF-o9>Nk*5($@tv1=W+48s95ex_vu1aw`iQ3TX8ePY$!pJvpzXiq%c6>rpz z6r}*z#hQ`MJCZ)eiwvkpp&@2qcQ{q%3P*K|tVhXr@M!ExmQf7Ug>ggCi|)CQp{o#B zm^aN%yY5jZ{F6wA)A&~2jQlB}nh-PKdh+c++tUkom*7np_rnu5U6MDK>A)xsiHe9c za)mJ1^aVVEbVwt>oxH@0l4P?j%+Pfh`!6sewC6wOy6 zGw{9p?$6=_&y$d=aGiT*Y=z~7CVa&`(P!&y6meL(!|0>f2p!i)ZEv%7?OguO`sGj- zytuwcvK)+*uLHe zNfFsBN)<*MI_y>X)N6guKX*;L#e7>hriJa95*AaQ6NjAqk0Qtw{##5*H$0=0-Y zL;_upCDhTED9EQ71J6Fi*jCv@z$s1`GX~KVv*+c_Cl1^MJ%jwEPe=9{o#d4ux%f)J~ zZg@|zV|LjrkJ6pdy1L;ARkH5EWN1q<`&U-O|AgyYgdzN;*+Xw53b6$ySyHAep^*x`)u3EJtH^AxbttbaT`BxmsR-v3=R zVOgwv+X0~K)Vgu*i}zuq`meK+`KxFaZ~&5jog&R&r!ylnQ0Uh=>i_k3ADq%D8vkwn z<$jq=XATi!=x@`{^DC!>g#Wzvzly|9nh=EkC!hTPT6UCHMKS{^|Ki{!1d>J*mX`_W zf^~xjYZ_(+cpQl<>{M0oyB;^=)w}^~HLXIq4owHD8SF6JQqkbXO?X zXd%KAu~%wn-NT-*ftcLUBBb?Wi%bmZul< zKTN3R6?>aD8y58NYpZyr-h9&b#5(2cnoRaPVS!@fgFC6X`Z|xgSWg1n>b~t1UzAzZ zaIhP_(BruHZk;2cI?t)+L2d9!afGd2RaNt%!>e9dVpF*ZjU`@f$}5*u-)vZ!miD=i zr)U~CR1a1h+spKNd5N_#X(^Q}(=nYhg3R_Z`Q62^wnWR zI(zl;3X3XPMOn1=kUZ$+)2P?(%QUgKrAqj$zypW3Gi?TJ>hkGinAu{IzXP4FY?cI& zuDIFuKpy)DmCkgeTCqrybb46v^{}hF5f*T)5|wmuEfHT3&cpExX|KkuodQU3yC-sp z3PW49WA!z&ebXtD{+Z#66_PxyszOx*9xi(Ap4Ca>Ug3`Bu@1Z$vbvm?wv5<(J{c8# z(TwgXK*3vg&=ua@AZ`G+RQTsr*tjC`iS^18TP~?%9ayTHQWmUe=SFoR0!%5Sy0i`C3?HeNY^G2xh9V5G%R$)YLV3T?X> zy%7yHAvI$13$LEHJpq>GW?XIMVUjrCniL(j?jFry3$9YMOxc;zrlxOtNJ^|J_)3W&77kLXQ@|J zkCfams{)mSx3wZ4mhi<3$Xv3Iw+Xm^NA!VEXj?R=b3gXIH@t<=Qy0m5n2o3x$oBF% zp~|3H!+@$$78XktqV!b3n~9Q-O1ocmQYU*Eh1O3al2C37)%f@mu$PplOd{lDl@Oaj z2oo>yPtJin^{ivsUa8)%eep^77)hC>Vs04N z+VBup@Oou!@wKeof-UQVgMfpDh1U9YvKSBxHUNlKtG_Y}!os%tXBvI*PxDp{WkU(Py_tXH5!+d0cn(v+|wE z@^#}b7h`5MeWWdWXxM4hWfbn$(^GdpF!M0$Y<1#NXD;6Ksn4PFm5XMA{mQWUZ@?sc zvEAm9Md3&I_%eM5%29-lN@mX*zd$!fu2m4e==LnPSwu@uJLQ=7f) z6XGKXdl$Y*m}6S-QBseGz*6&w!gocZ!!yKZY34V#Tjo#Db*0bV1H@u$p?NrVsc%59 z)E5mrQXninEbjQ&sn;npT$EZQGaT^G97(@gl!c#F1p z-=Jb94Q#Y}Bs(g}M zSB>)61D(E#%c^YN(j7SdT1dzcbdY^$Geq$Ue?gGyi)T^HkTulVQ$S}%#wlR*70;0* z#BY%5R-}kYj(*&`I_L4KgogbGV^JLOVvq9mIO}`%e8CV@eyKW>**EV0EIj#tQ+uM( zzrj|CXnw)rW<6ZUZjTNO%U@L*G}N(rxw$d2dFG9p5@&Y)C$5sb*DW#MM_qhQ0o-u} z3<33}<|&|OR7E-qo2u-zmm<_*8Z~n7F)_$Wpjp(jZ0p+R4VRJ@{`b;cJ(h#+Fm2q`5iFQBj-8DT7Gh@ z@|m3?<0Yb;IH&XPgAL5*-_v>*Ns`P+J;RA+IoE20P4}K#KGG{FstpbfNhGDSJ!@1X z6iFu$n15lDEJ)qM-Ed+1koF|Nk=-9{HnaHQNZb~Cu0_!$Q{(lDhClb@x73%{)t`$V z=NJ(YT_WN%yFLq|TAq^acXfx+fmxI`W85nA^Hxo}9z!pVP}gNWGWqzKK4ypnS+Sh4 zmc`IN$*B>EmYS&!mFqFn8wlX>Hq#m0b9%uMnUfIVLTy(1YDP%?nt)+k3-J~C=s83X zi)BZkgbMGBGKdNbyOnz>Bzi$@1DpdhG}s{=T%<`a4&xl7`ew&Mfog|`HQCsz0ARc77Eyzv`GWo6Pr zXvL6Ci9Ka)KVXgyq(Dg*8Vu)1xgX`ZkD>Eft!X z!UjhJaw&QC-3YHwHI$v*i(1BRGnubm#XaXpn_*iQ$r(A(9Ow`Sqtlu=VByBCBaJlZ zlj<k(LO{qM??phZ)Ho0UD zbb=sGi}%}d%*QB01t$_n1nQn9tuE)dNN~Bjadb4J&U%NpXp|27@n<-DT8bLyTG@hM zcXNdq5Fb*0x#>-r?$Qq6j)!TYp`o~|lJ&Kwp}8xuRu;KwBx6WT`tV`Bg=e>(RbA5N zCHq3LV#Q1o5SYM!MrHnJ^E?jR0-{4X%q zuZ^Rt2xi<>f=$xc^Di(Lq3Ke6+QC@X20^j)`T)1e{{`kMgB@-OpX@sw+Y?}}DgER1 ze}TDv-uu6YCM=7!Z#9V+wJ2`rfA#qRbNw~WRGKg~ecUBP@x55YzzXo5_7RPE zp|$5ohw-me`Hffatm9eyRE8uk)K;QHLoT{Fswarf3`$N4Xt0}_QU#G;2vQnCp+BgQ zodRy?hr-atgcJHZ!xi><{)USGu1pY8aGrmL?FwKC3(1*FFbor{IUP;#0H_i&Oqy=< z;M95Jexc~^gai2JXK3QY&Jmpg`r>9#I3_~kP%8l>{zp=s`*SP9e|S96f3cec1p5~z z`i)!$gebs2j)v#Y9VbBC|0w%Ehxc>#0Iffn^Iw*ne=|PO0OAa{e*2fwaPlKXMVYZMq9|aK-H;KnV-@C}ucbWSMzQ2D|y+3?^|Ly|t z!}s^^XwDzLzkgJWKYV{b@BQCn6#cC!{9B+K{0inEQVtc$O)=_cT%QS1Q zl$ebBXP?HsBAR$D-VX=P4Zsf0ADX@OQ^)$|;dJ|4c3n(oH@U7zZ9sEFhGW!wV`RR5 z?5eSnF6Y}MA$|5LQ1^D6a~JZ&*9TWECMoO*KRWd5O(bAZQ9)K|EX!sHdP3Sb*J^D? z2x8{aGl{*{27FJQNb`P^rKqAh=fiu_nem^&3LE3La6(`Yg=Q;oOsWNm2!UU8-(stJ zo(D-FMsB+;*=TZ_5l?CQP{(SD8Z-KoEW~%+??~DT;P(?8P!*hVVof|ytYSq<40gGA z-0d%V6*t~R+E?R#*Umjo06;r`gM8d7fC8P87l=Eb;SJG`^(k`qWs^Jhxo9p|%xU<- zXdXaCmvtH7__5$={s8N#@&sfovC2ye&x*&Qj`jvmBKhew+0qGnd7;RHm8TokVJe2RAXeMe zB!N_JU1PJ<@eKt9{qAh;+w>hZZ~5h7`Rm>ex?M65owVH_G=tt*Z`6+m6+{=@A3$z6 zZ0kaH4$|TvT^+rC_l~u&gW4G3mlcvMQ&;s3&~HrpY&%@0{UL_Bu9)JiPqCLDRLE%F z&9PTE7EO6}|JH^9XiC19#@x>UU6SM>4F}VA#!Qh*$ouy2tqO@A2>M#s1t`)Pl(KWl z5S858+V|J?uxhx~-7$5sAL^lFF6mL@-t{oU@Htqs9o zg%vv*_B&6L7vZs?(=vkAzUMh$E?;gF0`UynaYizhc-MOFP!Dv*k>t(bh5 zVBQrAiLYglczgW~@wQEdXH2Dx9xWK+dkT;}F6P-zMES1|CVHO&q~^9x0q+CWTzs)D z_#wPREWWo{@L{ovnaksXlDr}?o_^S)TO)h`J+5)TwA@XM{Rvw|oJ;gQp8AW@1KwtH zUak7!X0@83a*|TIXveV3{xq}UO%>y;sd{f#W6S1`mU0O@d|&&tMZo4Vnje|&kJ&aZ z?L!Cd53`#0;dEwssIbA%J*xg9Fw}Wa##T!(bu8A`htJ!qKqll>*&EVJ-4ELH(8L4t zE38Rguj8k3}BW=~L?(Nk_FRHkm+T%IwcZh|DuQd)YJ>W8Ja7fZ^`|F$D-C*J?+~^Kv5#yh+qY&a0J|r|^gPEYwl= zms^*GOrCeBa)|q4OYM->_uwQ+McE0@1*2W#*m^#$F(}yY<#a$VYdfaR*DYXNfw|T8 zZm2pbSa4!fEy&Fb&+SLt-^k`{Ni!8%1fk%Ln>mKjp0^4O(%OR?$>>;nVeT zx9VdgLl%wiVcOlZ$QxxHN~xSS!{cG^Yu zVGqo6bx+hf+{74|JDp|^JrnrztFgw}FT0Fms#PEOF7d37 z=<39emsd{$PwHZhz?JRb^9E^Gg2g1 z*iAB9th#IIyx~Tcree6-IXg9S(_pz&n=@)XaE?}b1?gEmO9PzadF96p{_u=zBn3Qs zRc!4}h)(Cm^RMX1@jyWh(YG;uuIH&YUKJEjdV$LDi5@d+KpGwn?;1buB$w29pP3df z7r_)9%Q8Rljr|P)+xsFGXX;wd#|3H&+v#Gx@}1Kd{A^~&3nSpP))SV5ysA41k)*LX z@%53i-IXI+Lp=f|by@W|ztRl{fp(*M-tfOc2MRgk7}rXEZ3JVv8LoHnK}&%UUx~sk7nwWs_~u+fvIO zQEO(fY?3IZ_2spuoz?H1B-XtlDl&eK=uq1}jpBSK5Yh}eoH114V=CVL=-@!imet{I z6wzguJhGThW=69JQ$*sE%ngApsBD+Rb1iJv@patgKGpLp`)I7y^zJB$DTXFiq_Q%m zm}64Tim+2ph^~xTG*PyrZ)e-$)eM^$2k9SQUbP%<$S2gt&?YRvyNwcw?PYW-nw;7N z?3ObRcS=k79v*9dvha&ZE4L>Fn&U)HQiQR}Im=2HLou>#(KC_kHy=4MjyZ)v_^4w` z`oUeI6WR~%UGNl$ZH?9Q!pR7Sm=4&SQPH0D#&hd@P{_s;>m)zUu6TuqXx4Qe8@%X# zN6iP55{Rs${W1oY7uekLZN&A*Blonk({x?O<3i#hA}n1TkOQV5EaRldw$==u$BDx% z+C3VX38h!#&O}DPlyXnbtu+>sNFPi;R=KCodq-O~ZRJ;d$I}J^sK66u%RQoE zD3=tK?}(0QK{@zl>a!Z@x#m!MPx4kjccZOi;vU}QmOXj93uIXf5NN2xNQKo)Im~89 zs%U3Bc^Pzoi%73?+wbuD@IH7+p0bh3;y@zsntT9bwtkYert~ek*xT1?q>%@bWcyyu zi2&Hk*H$EXFG$*l&$4IOn;yP7^zB=M0KU>197v#?;JCAl5imu8W8}%h6n&JgPxZk! zhUzYLc-=w=zU{V406R8I{l%PCUp*KOw!CvI*!2A6t?cc&Yp`HNnP=ZcNOJs%tVdg- zLkSsK@G~ootbM!*k}_>p5Pi`Eu)UX*K$-HBZRPSh>D8~g?v+`~a9;uVRF^pJfY%k} ziOL!GJbcJxsIGneFEZu-Due#Na-A&27S?4s3R|bhCHMf3kLLEIqNcd}Qt>XjxuN>H zCKXm>W!0%iONMn(3ckVNNb;#0rR$HZ$hhyk2sWXf3|_*;7klA9CqePi2sjV)S?vx) zR5h+ZE!~-$2g99Fw49W)@wTz5=DDFZ$13|>i!A?ciGi8wiwdn8(>BgFd)3h4fJA(J z^1u`TiR65 zLI!dIR~!NcRivaWy;AYH=aKIG+9`l#=>CA}I5=n3EHN?Bh4O2&vR2W!^clP3R%!j7DHnUn%a%IX+pG z{peVNNn7u6o7LKzFULq0H&nrAwJOIWWeo?C*7QFG%VCS~9d53P^b~Vn#V=9c2)T2H zO-g?9=oGM`ErmqTU(-m!i!-^$yzynl-F^JzfaC5X2UlRV?r7 z+fXcpct;4Fp07PQvTao!*WGN~G=t%i_3Nyxy~2S`qAJQ5(OsrK{!i$=sI1)OqmoL= z!*DC#?iqYksny}lTko7mO5-UHTPVkMy=>*NS<}5CnP0JWZAjK&^+n7>kA_?4fk0Qq zhdbcD9{c+q?N8M$j5sp0z?+OAR(u(`3hPdnGbWInR$ zOGfzcQ`bd$smfzLa=dXCk$PJ;l`M5%Vc%0PAO@;k+r3U=z3Y2xr4g5x*t)(JZbKSS zlMY9y1<0yZwPJiC3cdpE3vGq5s0hwL&sus{9ax4yX{WB%dsZJkxw>jyv6)Z)@>+@g z)Yo(uvMbD?iW{ucB7RbKaG0}g57^h^vBR01#zu~rDtFcM>`avzz?`*?t z=Pt#RQp}7!T6BR;Q=5T^aX|E(#z>mJ4fzVxF&|{*|DoK%T21DiomsT!4lTK?-*+?r}keArP@q)(= z`B)oBa}y7Jhl@`s@gjt;S3mFCIUiv$69{M19Fo*1~sFo^`x9~+cp79{~?59wHbZ==yg7!0XetQsk!bu zcbi^{eSXZXdJ^lR^7vwghiZPV&7^kWcjx^o8@s8o)rj&)tGw(?tzPnB5jg+#`L z)9Fp!tv`v~Zs@^sq*>q>t2Q$+$;(9MBVio;TidZ(bAB7~Eb z;qt{^crSVZMW|3R*yZkj$K%#X<+j%e>(o)!un@Lq8tb~bp;t6uja;3(9xGBT?0NjS zij|L5;7aQpV`b<&Ga{6S>#aa59Nbk(4m7>OhZ=Cw1uee#vBF{3#t+TN#0xe?Q-YEW)L!Wwj`MDwpfV@&eLE;JcM4HuVj);Ud|W{wBNV&nZ*?WGYhksIf&?@x$2oR<`@ z6QbJ*_$7jnTo9H{?v!8s`wLm_JUid?kFh{(5+Ecz`L}OBfA+tfBm^(A2^2p=@Kq(% zL^8~^;^`{W^ad*;`R|k~CYn8-m~<{1*YZ1@f1e-el1&1BUE;+VO!jKpBTi1$nmy|F z!^24CZ7Uc z|ENp!hYN+Ezv9rJ5B^DN0=NBSuHW?ePjULGKmf0Qs?6W4pZ`~j#L{lJi_uQ&)2O;a zE2R0v1k%bvGAF*eB;V1JJP}};VoOi(%7u#OJHQrUJw2q#F1;Rv^wQt$xNv7>mZr3dBqEyoR_A%J&y;D zClgVFh-;SPJ)k{8b%u?hJxcMk7-z%$+?n7L~=YFlh%2O z1SA*BZ_*AZh_nN!FAXLRF&%&ZaY&+QBlmFxbDJS{gPV*d7Z1uRZ(MrPqt$}{)JM|^|t$d@+W!n=UDtMqaS3r zP20GcV-hN}FT&k2mifN=DBz@!Ub>#8*?KsQNU0>0V%N6nAR-aR^QEV;+va)BDFD8f zxw&hZdZ_Nbi>jCk^&X*`LC|0m+l_RyBVAXySVnl1nuj_u56ttDguyDExoXtn0vVZi zjRn=7M!hT4$+w>59h8#Tn5C~!G~<)kdELqO=GvkiR+UQHf*0&TwI?5YZb9v(_AY-i+bg-mH07`FdI;GQ|$1|rK zoSd^Iq?jR;2>uOvihv-Y{~t=Ji+vZ2RIL}11zr)=S+J&Un^vNZiNS~? zReWCQ=(@b5j?u@;v~RV87W{Q48sm($WOpPZbE=r{r_YlaU89yE%22n*8n;=3B5_yl z!JQI8E(7qno#IWE>gcDA?8xa$D-)D?S=dv+%~701G1g5#b#duV|1C+pgd+>OE>o-Y zBt1PWdyG$7{mJJ`0@VE@lWJd=KV;U3OGR)q4XNm*a#at%Na~)l{w@iR5fOrT&n0+t zS^MQnI9_R*4Akz-@^V-^@n2RLJ;GNgAw>$}oL@H;SbmqWX5ZwGz2jaLlR-ooa!$nP zr5+~u!I_Wa*OA`=)#}X6-aB)l&sEu1V^;8d!@}k7KUW*8D0%dJRd^)(#-b!ATtUYv z;w-WDJErx30Mn-73p>iS;y@kDnUHd~4_0Fn6pn+7ECiOh)zXkX3ofO-NWWVFS zfC;=6ou(XeW#9MLqA3I5tK6v3nF(-ZfvO)yc)dyv#Nec~6zD;Pb-h zA;N8xd_4_fe702Eqa2l#0qi* zCwaqK6chU8B6FPfHwVT#_!_BdyLhKa?u}e-pNYEYjhaqt1-(+>zEF?3lgiPz7lMx8 z3YDw7%C|qeiL}_X6czlGYH=Yl%V-2$(EefJ`V)&TfIpYIa@`cc=lB_nF!O>b`mX~C zaSP&7>JCsr7dR}@@A|RK>eIX^6}4I4v``)@KP&&)m&J~?FqX4*{tVlfS;*+5%Ot&A zZ$AF?D%tK6@M~R@z9qH}{pA$U0iu;d(1NA%#(EtKz^rfWog_!ZbvlJT)D7AKwBCyC ze(TfX9L+YoF)*?`c$_jiNeIo*MTiHmIDW+opS)GkE=oJ!!41#t27BeNY-68LAWe?X zB&|MPRqW#Zj*|V#WpL5#p+R&a*?C)bEYU0%>ugVSxN!X-kN)#E%c)QO9TFkNXBOT+ zx|z=Qd5WFl-g}}~4Bqg7%s2jR4oDPC9OfGit*cwT;yVg0M11QBxIL{(fddW&ocA`n zGbn$h*fEu0$$Q*{Xg)Ax?pZHyr(H1qBoWSL2Y4Q&Dc_95_l!zn;5MUD9#j^7WKXIs zBSRwD?p>`a_97m)>5V0)ysshtJZ02)-i~=o?#`#YtPN;8ihY-PF z+Hl@RAAmM%isrK737O)-aE$~tvSObu>Tqf5rh=tBJflW*bf8LPVMgQhx4$0SC%Qe0 z4El6cYF~R~cMW=WYK@x$>wzIL=vPrqWlg({k#A`zZz2ue*t+m;-9h@6*B5RnkykRa z#^sAgo8eUxIbRQ+A`}Y{#mOMm6}g0nc$dsWVfO|pIF2f7G5RH}JhyI^hsN9M)E7@$C@Gb`-T$b9ShISvy#r(?7WXvGP|x$F(y}Ahlefg3>=h|RU)C8)eCq~ zO0g#)YJoTSZ?=Yi&K6_T#}}YZS_o#7yqhZ9u!sM-8QO*qP8|H$MC+=?k?hg|hFN7d zpG%0EF`i^z^1v#h``+v-yCuI%)=NY~UlpmaW>2hG7FU%dhUJ4M=pk9QHX25duH08) zd||H_1k?hbP+XV}BJFY$g5S$~kP#}*ft(?wF;2n zlk(WY3Cr`~r7acxC3Gw6V55Ys7GOi9L<-Nc6iP@=iz2Yei^VKLSvnDd@mNFHr5w%? zUhHy(;1s}w$E4&i|Hrq!#`Uw+zY_T;C4OPIpOpAtLJ9WK-&>%KP8im}N`3lCwLDv_ zBcAbC|D5-z31ZYwY+(FsW6<`M?7__&6P+Z0`$b<4`NrCbCnJrl0DrhJYvG5c(hby!+4AE<3glAixqKVSrBd;-jUy_M4ldk%u{ zmiTcM;=5C?4*4mf7kiERJd#Uuy=^5GrUo^Kb_0<@xz!RI$`iINvd!$=Qo9is2G5mm z7jN5DW2)CriV2%}iX(GBl|lIk9!Bp0s^j+X4xLZ+NnP%pLlbRWgrErm0CiF?^Opdw>}wIGsdPfKvpS5bBAhTkt&u#n5lU9T1XfYg+aRKxa zRqk>Mh-?(~MzosQGFJ~Z4$tb-_U29X$XT_gakOz~GfKTNeWj%Jp8d|5mcTPlR4<(* z)jyVM(ek^R>HY9#LXua+x{JhgLv`4Ns4bHq2>IN}GHMGl+B1ee*$s)%C+ zBDpDp$EB9DqD;X?Z4(NU*`MH;DSamI@J$|y>(gAY)&R1`s>vdoWiLx-ZO@#K4@*6K zNHkuNZE=b-yfV2J*WjNT?lq#g0!@jJCqPv#H%!C3k9PL()k8ZVinBw6ck`i)%I9<{ z2P%5_?iW!ecOnkhH=PRB71XFkxJUqG#D2z0&lLops-hlPC!s1}T+`pW-A;wh+ zFAT|`vL$SCeqd*@%lI)2*$KJj0iKiqD<)p!V*Q0@G=Dj<-rDbd30%HGu-1fspmMdq zDnCNJ#tjyNHTLWWA}82Kramu>!)YEWVhw*eF;hM%pFMX(SGk3wAV7W>qc_s%V12=G z*tA{>;dOZKMEyP#rvM;5UKh{w>lrhl^zK9KbNmZQUxI2O;F>yF$BwN$ySxw-mXUxX z+5p^be;LcqLH#m8KWFME`~8%upNit2SLx=pdbLNv8^e)P$zEBj3YZSrv8lK3aQRd( zUd!pN1od}H*FF0F1R$oD1JM0Nq5rDc?+`Mbr~W|;|EM7Iv+4gi3Xs|SO==6N;x9!< z6H798@K*`;!(&9ecl5@Yx$dn{6y+YI=X^Jm0afu-FN`VjnNY@)+4BJ%yf!VV=e|U) z7z@po#G}+FcR^Rf!|TdD@zn}`>=?V|G`fww!+OQSizP|S>$L&tlGBNP#_cj+3huBI zkuBI$7vltmQ@mygZz+hTF^3#A^t31E5Qxol!(*S%a0tUofw zoG>ACzVj{5`#isr?Z@vhK-HcR6>r|fOQjb0?*ulwZLSC*n7O}f_RKYeUc3F2UVp`M z`rbLosN^=}`F<+ehR(b5*yed6cvuP>Ly=58-q?tnz9!$-~to(OK zlJ@K{1)ncfR~*o{j2GsfuSmY4yJz=aevA)6yOgO$Nw?x|0DtQ$rF2d ziTqcZzTKje#tM_yvZsRrJM0uNLk$k3uNW zvjX3ckS$T+O)J2$!r$6f0*x;9uUigr=2i{@B4YDJ0l|HSwr1U(N>M*J*_b&zFt4}X zg7vqC6q9}Tl!v^7R$9yOwj&ET^~JfR_@_BoH_9B@zA2l_+myv1pVFaCws%8)hKthNptbf`9FU|xs3mS z*r}w>|7`KykRzYS9jMxI#5BG{KL{3-IL?v<7OCS$cJQ-;B9XlMyX;S)2*#4p_=}JA zV;>GbigXw~tti%Z?YY1leW>R7H=pu(`v|0%>@Lgl`+YEhTG8!0-t%0sA{B;B)?9O#F!JXI1=`!7|$Gpxn_mD@?O#nQMyDi$~ z7af1b-3p;I-!8uwRXyZiA@+hmqrU!=&gc#IP0VKcsQ%{cZ>%1O!Xb^;u3#RViNQ@J zk9-{Nof|(GXu)0tbY(qCwexKc-`fi9RgKMUWNKuD>Uw5h5XM?@%z0j2PH?4(0E3J8 zL-Ad|J9b1gWo6&z^TvdVDf7z|tp}IG7#=?sYaMBuyhJh&;man6bjar6;{_J8dAz@@ z_z>iT>vb`S% zhbU?qsUxNe6`pVM-f+R$h@z2Yp`y-fn%*kCjv*g&wnV>J${4wt=pgw z`Q3WAS)2!Mf31-`pT-{BApVY$0$qcZN`XsN^&9n)B&75BZWo{Acgf?D%}HZ=_2zM` zWcnO7y?Ec&RtsHOy<=f9yz*jgqI!T_Nd>8^+gfg|A9d4G8RQ~Sx?1*+1%I_zY0(*R z9&F9c9P6&}9lN+OBV3t0AhNBzvAZ(F_WTze^G~82;Uuy-`xw}GV8}w7&ZV^U*vnhP z+Du8Pr>D4HA#D%*99tZggrF|jK8HaEWs3#*E0Ws~%r@o8fzo$C>rm=nz3czgKNs@> zq)(+Fw!i2;NCS+F-1TLtYc7&Re|ei@%ogsFW#}| z76Z3%(^BF+H1^I*6Ph3eDAJlbl8MFSU~halEN?LNnv#tT2xMiOd`uF{BwB{#W!a!B zCyileSZ->^&&IojN%9{Je0(oUgp7)D$GNd88ryRN+KR_F;Tf$Ldf$!ve+-Y473PaQ zvU&Y|v0q%n~$68laEz@%#>M@&g^67fnz5LydG$hlol0`V;I;m~Goa}G|#SHv| z9%4kbuyFlC?vSIcgz*4Jyw*ABy$I0)?Nis5HeoNXIL2Kt3tv@5`FjyTtP7^)ZdlPi zsXpZiYjCN=?F`eG6V{(kU|2P76}Uw@CA7EZ`a5`ju>N}Yc6b#Mzir~5-p=O3 zt2|5yq+#dNwitP5P|OI|G6DttnG87wtAb~LPFVJhZxV%^N?tw1E8-;b zjQOHgr!99#Nad!zmj^1!=|XyX-3DOGS_pK>w1Nk0U3S`wA=7DbYUC#BhXc?B2V#3{{vnw#zox-iVCo@Pq*dxTUvJoF2~kb` zu;!5ZP{iy#eYY_eT^H9aBk5<`AWLXs0Qe5{0o_h2{*d7}WMHT?P%G_NI68Q?ToI_8a&^#x ze}mCACj$_=nJrZF35Q>F+KQa0X`|mNsQYvPrWHu(Pcu~fqI-jmz>)HR;_RU~DcBNV zgc-NmQ_S2zROBwn$bU+wl+fBXN%SYY=1eaW;!QHz6e*FtSptv%kkd@;RoCEz9g zR;erNP@bQWP{HfOI+4o^W}c>}5`()GkpD%isgRuDhTe8jj)KwbALTM)j+vdW7H&cc1(^}d zU~G#fg<}&&L9EjsBYJpS-ozQD?93W|p+_@GU1K0(&gMb^FZNd=PPxB{rI!=i$R@w& zo>4Cc5*^dkpO@OW>}=RYI&`EGABFBJ41NBl-xrtiwiKa63XfDO-0HD!u9Gf$*8#^z zSxqi}?>RYf`Eu2?pdlAu;t#AU*NRsXBsV8C$H<$hY+gS5#j3mpxCkE8sob6$2xZN3 zl&v}LpwN7!>Gm~wiApXb$+)NQj}7tMnHBq=T}yvkXa9UXwYX_M{OAP3=~Hpz7FYkS zcUTtn_q>tk)?fOF|0fD*Gkz+2$JwOYPk%dkQw-@~GhaZKZP}OFs1I0V$@>${Id%{TmYjO)54+rzvzyA2f_t! zR5O8uK4ily(pcXD;IHNH$+iQJhv)jxx2vIcvOe|6rrbrfhE{3jcg6e|i~w{BZYUai2;&b%&2DjEp-2no`Y8w#Bb7bxp9SK8~0*DDU zKu{Ipf}+%c{_yBNOTd@{GE0Bm+h6VWSAYBe_*me~g_rfV`j&d-Epxb~ewkNE|GMaO zt%?3#ilj4xNMIE1?@L~ZZ10||_4?s+CBmUN%KEQW@Bc{qh(8Z@{$3dC(vn47tEO0y zW?Hpm>m%1B`b#FgYht)|xn?-8zo9o)f2rMJ&b#FIw?bO426(DbyhBCBH(=r|wz{ej zGx#X{TaxnTRDu!r1%2V>x?<>)qVt#7&Od&gl3e|ZjvZvzrkA%i)EkdI27j*@E>s>t zRlG2Q93TQU41mNrOJ)x*-=fTpOh@9XbRquqayfeN+2+|J+|KJKcVtnF6I6%8IO;h^ z_nl$8Gw7Cdr=tAv&oB{A>!k~AJUbg_&b)}#EySHad&KBA9kJ2A-JXpKA|E|aJn(Ir zR7ra}Vjh>=#jGcxBPr*n|JBfCF7d|eBGxZc=IAi0W&y>Z1@9D|H+Gn8JRtw5vMMAH zgywPMqyL;z4|ETr_9?8P%A2K zlX|UR2`0R-!`TU)vS*9uv2)#RdNn;>h?#}zq+9{)>0+`jlQ6*u z`zc#6k?k!p(AK_bcYkCjv@PWYzwajA*gdH=Sk@Y*OlBgm(=fQv7Eu ze+5}DHDh}0tX#t#e@$AY+k#`%zUxc5c3n?>QT>z8_>((iuB4l;{G4JH*B{=h>RW?B zt25OP&a7^mSa0lmJwAE_Dl+hOLyu#;Rr1Lj?t~-rncIz3Lt{M!dn!qR)x6%!#*k`s zX0m-&*_e!sL%W8-3=l{NVPX&t)9Xw!G0Nu}1ZqEjwqTX5j$!*b&eS@@w6*e7?fORg4unrj+ z3IoiZ0!-h5$HBIGP~occN#L(Z&HBxGjPUO>Z`+ScoJmRkh=$`nP3+raOp@19h9}ag zTvYY#iBfNXL$wo3ewR;Xp8gr?eHAu;;2c`MwVciEuh6%L>4T{3a7spLZF#Cq-h4ws zyc)}5^~P~)U52;llV8+jhiRA+ZDGchWXHI~Kpru%ifYnao|#>Tt5k8%Q^twzDfEPV zNn8|#r6MM3cU5P~@A|pTx-7Bw{304Se^Fd&tSRavfaW)oj7$a`gEo$nM3;@C#-+^Tt)mz zNZZ5tE{$1tme<#7OMY?`*jJQt9%T?irf6m{R}J1 zHwU*W+`71R3SM#^@0&WfvDf`ftM7?EOPPVe%pqR~(R5WXm!jB~TH%J}z>r$^Th&CD z_EH043HaQ|ESLB$)uhmqxncKRLuNdSM29m-2A>0Tt-0_nt0HyM`5wiiw!&j!pNv0I zd$kN+eR+)T-n94p(p{RE;9I7I@F5Mf;5es0*!q5Rl^K}3JZf(_Y3ktbGIygQY@W%; zVLY!G>hZ~lNh0cH$=e_(E-O}MqYhFZ6`+DIa{CG89_s>+^{pJ7Q+|JgW=yOXKZ!U_ zT5HUwsJHFfu^%|Sb!lm-JNBxs0UvlnG{)LJD`HY-{CM8OPhzLKB=%5co=%<{~u`1#Dd&f>O*9(hLIUx-6?-)ntX;@*2~tefv89P;2QJD%Nb z;aY&?j>~b|D-_97h7{Thr106P)8$k`wcxcqoism&y~~)ncP`?U;VlFfH%@}^8R3XR<{zVEVw zo*YaG%~(v;16WY&Tf3vy7mMfr@0u`Ws=C~RPL{wuys@s2Libo9l_V@~%C z-xYoJqllJo-tqhp)UoXevo+$F~Ig=TZ{aFJu5BEBWGgL4L`I^-Q~Ls-ISj+ zn)h{~X;&NVop_YtSL5!R(r;~T9k4mJ28GP7Wj!~lLzFHJnBWYA4;M8x)hk=q5Psyl zW+T-EX1HF1b0IEd>riWQa`Q$F>A;}S*4PCtyxumOP!Y4P%j{P1KrXyn?wU!tFv5ru zKea9ZhS*)MAE7c&>w}r1pc00a!`{ZQ@!W~FqL-}x!v5GN#u`wOlNzaV$On@JMaUj3 z{Sfx6`;%&4_!A40BulDZVTaV}`&3!hvC<|;mGC&@>o0V^q5>ff=7(8`qot6a=CyrJ zaTY2)$|+^}KCpuEjHfwAHD7v`Hnh>75_=47KDF?M^(q>4c^%b83#tJ_17`%P8O6R5 z)D<@Z);9zE)NEsh&w2fHvrx;6$C4MZ+fRF5|sZITX-q2i&on6f9^LcK( zoP1XjIq%b*yxJQ@)xeGrc1~4NVu|*w6bnm|?#MdPp2NjSJ%70RL@3#{T58bDo6|-v zO7zhNcs9~uQ~#QMT?tlT(HF#9Z5qKjZYSz|r(eFx^?|c#Wyysuxx%mYeoXS0>5Vy` zU0{;jTRcqCxWKY+gFHnR(K?!apEinaa@EA`=!^?8bYFU)dPe%SfBTUu(H;^`{pL}~ zrKrI27Q#y$&q%JZvr{CXj2lM)c^Dw$cK1{l4(rY_^yNkGS{@VEG0ll$D2HAL1RVaK zWXgWami?!nKkEK&M)$_|E$${A-wK=vD&MZpWY_8UwwzH#o4UmBbY>Q$UP<93ruaYH z@UITw+j7U)jvVz@sJKJGmt~C40WW zwxeT9g(}cNfQWhBq2dM(%x>&YAXOedc?x7aFwQR;WT#LJZeptEAf=GH>k$5g(H^K< zs_&|-zU0PQ8JCs6#o;);E6SH3BU|q|wv#ZtqKu1D%PODlWC}sZ6n)MI%dt8z^sm)K z`PL{8Tk`nCnZ2~G9Ox*rOHDf3;mw#!mK+%dq*^MyUw$uBP#UA;X5am2 zbhAigLm*mKR--ocC{Jz=;>wpc0HA^F+2@bgX3o^tgjo0c7-{HuiXM`=4Qua8yi*uT)8Z27PCj_45zYpk#=#+{<&&hJ5?m#x6_@~wQ|*w zazs*3LDVa`3#kY4t^L<4VvIx1H<%=_bw4PsfruL(zNH!kk?}1}>uG$J@tQ)|9p09tgv&*YyUrGGN^Bf}0hXzT|7Q#^8)cBRj6@ zrd+qy-Fsg8J-Ngq$tC<$Ml-0qNuI5vV;HH38LYPSQHPozm~XTuym}m1dnU~Cl|bYM znc;~_!sq9E5m(-o_IB@7Rc+4O0QmP=b$nMH07e3G;Ty2TFYu8Wzo;t3IA5&b2cZ+B z4co;UuMQ89SdCIoaJN$f_i?D?wMQ4njD?LnlIN1M(O60%IbdXZxFFxvgA!;Ztxl#wl&>z_edj}j;`yFL9sF;Wy(;e$!{AwU3Uk) znf)K~35CwRBUJV(EW~{6n$t;%yQjZ#*AvrIf0t;{ENdSzf_Km5kMJR!ST^Ud8SQva z34rI+stml?d@F64cUz#1``CT9QlXbVKQ9Xx=Iz!~Q?NE;+tsV3Nf>8ES;gUBbn1xm zO_)Thc$GeY1dOs1C28g6yZMe}oqCWSwDoZ`=SI79GEEadWxFbTl7B;m=@g&HOca^0 z>hI`G0*DE1H16-~>poXCPJ^PAmZ8_rre5SSOnmg@rq;5dXo|4Z{hFj7OogCI{%|yr zpDN|CoK7_py)|MLq}uy@b+$fu&^j;4@O#>9_o*U_mt|J3=sJ8J{Xlkz@m7*(6*(qE zQ*MH*#Xe(i*n^td+8X8pOOsOx9ml$S<^&L>(wlJtADEv*%d=@oKsQWQ{zd0r`s4?( zKM8h#+qY;07!x!_<2CD=!*{2jyRT-qq_5%10Z+UMu)!NwKHolD9p1(&?pxnB?EDoZ zR5^=0&ZN5Xnq7`X$*=RbgIOjp-HD8q0V{c3ouYV32%b zL3t)J6kR?VZv^b$wB*PtiRH=@J!6nzGd%M<{tG&+tzf%}x1*;pq2DCN%bpdVC6>sn zv`rm=A!Fck%CgL|ue{ZLs>6KFF$COe2H(HF(9=nG^-*hFsHw8sB=A7>sQSr6`Qcrh zj%0dl);=u&v5Jz9wP!_``)dip3)=SQ>h^?qcQ7J}u8W(RjjOdWuhG zEsjZ(*o((B+p+hRR||KE-fV+7=S?Q`KFp|EJ1I~UE zbz)geG}EL#qgZ+IlQz%oHE==VoQ-Y-Zeu8n$gFDN^r##0v*j1v$HVw=rBbs=c2P<* z^g8WZbJJ2~uhT#q1v07ZspTLIuFjl&m_dMNYlxn^5B2wyAv2}zX!?(iwzM)$%9;(Iw z0!$P?4pB{>Fz}j=9)+#+^WRP~lB%ldmK@JZ{OBaXAlf97m|%kyRjofLFPMg9eiwltu?;LmKb2QejvzM8#>2A8 z@@1OThrx1S$uX-KOz(Tpm?m$A=kpGmypSUmr=l1Cs5qzQQgKKw4Lbl>X@L0gbFMu= zUL9Y42uy*J0rzO9hnz^(ZaZ2cb+jMp6Oz%ogYIX74fCEnlt~oQz4oc=KoE%#h3pRqgx?PuPF3m*q^U4Z9 z^){d~P_cA6dL};$s0ST;7)syY4!$!e-JAT|6=Huo`0LXDH(TJy-w{ULKU`_jq%AMJ zOL}`U+w0xS6Ow-W_b}YDCbB)J6wnugRloe$)90s~4K}q<`XUjs%lZ24+Bl+PGG}vu z7BoX0qq-brUd;jo$=<93W~h3A{DO4fPOlj1yI%{AawZ#C`yhV3rhB{bn=o?j-wxie zDAvF?X(3oqpzy;3AWt(4#xwvppf-UGD5*uEXeOluP0-ItP!Fy>{%;4*E?`GzdiU9W zvr%QZ3xq#V@h9Y;hfD}{K-KOXpy8l`L2LnBNBA!~m0xs18oxWHYd&y}2Q8=r&Z(TH z0Bf)+sInt_OO&)uJ6-@V5%Cj$f0(}?{Pk4-_e=ZhUH#Pq{~A|+%@+UZ%q}l`W02pn zacDbm3^H+J={WSn$7+a+`Pp=H)5N@lwF!+h^$+^r=|0QYz5DxQ`}YHSq4Ti6&G-Kp zcBgaxy7Yf@3#dh%&H0zAa;F;rz_8ITx^dW?O`{M0-%6d~WImk3v?=>iz;KZoez6W( zg+brN7!qTR>&4$N41T?Fu5%?UIoZhF<&M27RgCg!#wol_1*uj0tsv-)Ow88VoZz!! z_^UWu$g zi!;1t{T=ht3p4R7O@($TrV}Pz#?~|oD3a~ct&uU~V4I$^%RvoWrerhoZOwO4dj~}H zswgyf04BV7I`^-+EK1qV=1%vS)OP~x+fY#$F+qxJJ|s)PIIz*6mA}q6GtVeU_!Xb=Xl~rq z{A>54&U~?Xa~|wIUUZe&yj;}Bczyysxf2M|w)Gh>rY6-Nr2fqBv%3#eCPffxL-NW& z21L0@1yYImrcqf3QC8hhs`_4JrgNo=F8~MUXfaTr7JaRi4WFAje7Bt;FJUm^vrb=@ zJpGG~%hHwr4}e#rw1{_kOVA!|{`^TfqjSMB9&-&#`8O(ac0Yi< zy`f+ti5c79z&2t6tg;UD5Sux)J}ijLm;Yw52E@Fzj)6yC6O-yk_7Q^m{Qu%PhE6}P##SP6Y_bI zlkd^yy}DsO;k3!M;S;4vXK&hBO099Jx;n*jaE!fjKbaM0beKuSm1XX;2KGpez%+5a zbA$UQqsXY>?5fmkvO^nCAQeNM9CzDEJy#@&Wh1LWhG9og@+os1t$jC2EY5ZYi{7Yw z7`!!kgltz_O1(wN%$uC>$0K8d99UzttQC`ztn_4Ko-sR)#&_Sk{Jeu_1(22jBOjTl zj}=g_F5I)|$>u~s%h}-UZP+s(F2ilNdRcAq-@UJkk9zxYXci%R^GVgFu<&!C+Jk;w z+mxZB5BLUZ4-0$>m2J&dC}+lK96hpa9`IZ17HXph57Vu3B4y%6Rt~H$47AmIzi*Kb zh30z3D@$%VmstdF~_5O3C)Jffv)fZpicv^&fr(H!ntQ(|?y8{mySmCr|zMyrlV(kd&b>8Gu}Kft7H)OaLT?Ms1{*Jbt(ssMS+ z=b`^bMDKT%6)!OX5-oQIsx@;T#j}LJ1zU%j_czOer1+TA9++wT5Zy4p&>@F>La~u8#c36RWy~7NArF@RCqplx1Y*u-53GDou`BLj4M{rlST)0<&%8oKf$0;cV4_^k>iD8082RLq z&()?Z$1m@_=gjt$vX=`2)t{{NyCb3lt9R9rzFT#s-hQBeR*H`Q=O(o~nvXz|v61BU zHlgy^tub*nint-g=OIzv;HIr7ID7yjoF?TRy;At`o89FTjOe*o%ZqXjqB|i6`tT&? zUvx)pC?idr@VhNqs+mxwz=NR2lM`d(hGE7ouu@vDP*Z=-hr{to#;3gT>hD*!u)pXI zt8&oA9=^7|<8h9~i@2^7Bb;tJZZd%B5Bl4=e{5ZgEUMsPF4cfs{luq-`Lo*n-e7m1 zt6Pg}r3h1zIxM;pDYn!0MmK_5ks9ePrpNX6$N0?q!+b4?rEC@?H^F{^UV><=zc!%T z&$9f9Yh!I%o|uTH1PiLBtZ|Djs^^td`(iQzgLd`C%(G3XrML+PhdyIG6wY_1f6s$m^}Uljq4{DWrp@+mx?kpNUGt3hvd} zAB>b+nk%CrXIr`UHX<@lYzpy=FTL&UHm}OA0!3+nOP2#sE!jXSBSAHM1-jk=u8;eC1)Oq8kv?ckEoXQLdmqK3qMR%oL zWv<=s`GLdoKIXZ1w&)~6CEA$euzUyZcQ4(PLk_)ziS?D6h070*=j|-2GfwumNznDo z(ee98j@??a_>Q*Y*p}F`la_`SCisFCNvXUP`XLkj_-MV_1Kmx z=u=fTBnzkr{&SZ*3jntNS>-)t9uHczm5Hx{g%trQ*qRC=N_f!=0{AA^yxkGDRq3ZM zQbMbq;OU`N_bZ*?UYAd zTLu4i48L~!MOXcl@-$1Sf|5M#^#)+2*7;z|S>v7~@Of(0B^%LjY|rHucSLU$C$nV4 zE4ddJ&A-h0pv0)R2XSup!9uE0TjG@KRhg!yBT}_h-vLb2cK!^r;nxn2gICAXxlV}7 z77|`2Wd7jtbX5eIa0gOL_6urNQUQkoLhj97`+uJN{`k7f?05Xg?)jbw$dsn%{>=Sh z4dxP2#e*BGm>z#eIU^5e$ryiEhD#++I#ONIBBf%z#Z)MpQ@C&tr-sy2Ipv!1Uh99B;6HNjb#jOK?GD}H9_dD*Ix6FY7TVr7^bcLns?N>MWl~{C zNjUb_Ps^~$_WphK;=xEKRyp+X&VxKXJi|$YuGf{16Q3z*n2<4_Xp!EDUIwG zsWJRvKt9JmZ&c*Ts^s${8w1B%ydFFjzpe-VJpk9xsqx<|;r|JM;(zruqCS6eQ~&U7 zDL+H`Od6+JlfV=^sP+@3uKIfC!NgMPdNtnQQl~s-(l+OI2D9i7bJ)xIM&I92ZAybW z0-wOcBT$cf8Q)=YmbDoBw#35&G85`B^%?qorz2r2Yx0wVrxG7s{K?YyrNju|x3w1= z;M@|=1P~H%6#waLW?|gwk(|X;JPhAZuJ~;u$8vY2b1d^y`>o4^BL;fPIgmyi^VlW| zo>i(f0@Rs|*EA%Wvp?!Te?u`KvWKm22TqvYA{z@s9z}fU%yV6^T`fHYxl4Z z(0g)5yHRIH310~z_CXo-6WgNudjv9Wp=wl2S^P6jcmYqVET;H%;O(LThv3o-JEoS{ zr|&k->K3jF;z35=~mnVTJ^J}hKtCuhDQ<2Uutr6$R*#N0pn!Fod zy4`c8U+|HdLAZCM5*&s%OqYiAyBD~=l&!G*-u^s}SX%A7c>&p--m{jNyI{Q=hc*Ya zi^EnFRuGyD)&_|loT( zZ)Eu1eWOqHUEoQY-#qGdhO}&w!o>j?6`e|WVFo1K5xvEndLth)zYDT!$+zst1J2J@KC7F!g`j*zT{0qK9I zZj8BaFjGZsWfdmuT*BqrM^ZIL*W8&V)GLx#x9<3@`>*d3=E~}Pga*)EuofzM+yl!9 zv|emgS66g4Kc%^)m7zJ|vuhrp7hSWUEtUUtvsc0pE@D_ncaS#!DX=`0rqM?`1+Q$i z<07NOy~j*BjiDOD)+1rgxFngViPL+IakL}B93nh3nvmhbylp?mcO3~jB)>MAI9VF! zHEl0uwIHM#Q7$o9t#0sLZ>ZbCkyAmcGVSLmM}mIAlfGNL7%^@9sX>slDF*J)S_h&^ zssrkVj!e-&W~9Qob7Ku!aG*uFJl{K7v;L)>x;n!&TKFzo*2MdxUF17-XB)VG>_l-f z$UZY2N2DFBA)qoLRHIT#eG84HZYdLCI3Vp`b@%!Q8_3`>!f_=S8Ei6-Dyl~kj5mu?~_lOs zARC2dC-#c*F8Sh~8pZqlvcKq{;EDCZxpgDVA;O-TyfJ3H1Z+`S;=|J8Tj1rTrOL(N zdQF{Hp)3qM*>y!y)<-F+T750E}3)U8>CG_(sTGN!ft+0FQx z(&&S+{Q3{6y`4T;^HziGD&C0DgmYixUx_?^kicRuK)p=PiY9l`WZ+_=Og6Q+?+)LU zS@~P}`xlprczTuYws`S2e*Wg@8aibV{;X3& zVAI&#s;H$U(~Crmxl}{dw2rELa4UT)t0Kh;P1rg^iKYSZE1-F4K$YuS-{(Z=0p@H~ zfaGM3*3!pKd+ELOy++iO3)gNY!JFplS+MI0m?GW%yn;P~aHydKk=dtf8%dsUhj#04 z<(@w4H4~a^X%A5z5?x%@!X6_1d!8x+JwnBX@TX}ASS;@3mbe(LPn?;`KOJN(n^N(? zR<*rOv#RT|UJhP^Kh@PQr0&dSiA%-@TW7Q&-AF%(RH=wt&;tx}X#b_2`Gvs{-6L&fgPM%5@L_i5Y*g#ro{=rqoEAKyCV#y zp0F_cri$W?EkRCbcVoG!H-z&3`a1p#WHihzsHPUdgQo~Y(-VB_?b zA8_$G_%FRsi8X7&aG8Bb^7eAz=`KPeAbpi&N;2*rG56C@wLeU!I?UiACI!fB#na{C zNIvqhM4~`71Q&tjN}nfK4VDrobB@)hOckb|Ni_Uu+Z~nvL459LKhCX}!40WIF_7FB zOg?G19)g<2RKD7Pg`vu5>j=P7)v49c+4iD5MrTYEu z+)z_mYrJ1VGq;vil($@a{W^chY9CTS+#a88V4wax1B;C$C+iQEz^KAy6zSfZl^e6L zs>{(uWvaYmRSKQ=f>u9=(B}%4^Ynurx@xHB8clVH(^I8u`?(IYMmqLWqgf{#S(At3XXO={J(&KewrmYhiWQM;z_t z+#Y7nN5&$s(H6&$yQes~*#cxpR9j4isn-Uv!tu<6MXYkI$qiGAAxuHuv0t&R?pl9N z8$+>=AZPBL-kVd!3e*d-nQsxIlu{D9m3DpzA@QE#)m}-d!}r?)R)!l`v=p|8@gumJ zXaIqpznS#H;sSEn)rP6XG3f3e+YQJq{_~A5DP&Ou!t64>sO=j3Bh73ekWX}$2^(_kHmr{>RWN$$xsg&0y`u3Ym8^?o^JLL)6*(D2 z)#pbR{cm>n`6sttz4zeyTx0HZ@8=9apBC|eToBQ^BmdT|jx9RRQincbUgt69 z{2bA6SjkMCE?&gWm5c=ik z2}7Chksa8Jx9F`^=%Hpgg=U-b z?&~gUm@v1u>qi7RWnO~9?o#5(7yG6w$-`A>Ya7qg=1?{Kq&nC?Lh~J`QrA+_>2=%i z4#nqK?!&iOF#=qtZ3pD`q4sc=pOXW_clVjEDf7&%Pp{nzuH&Z?od1L7Qj@GPQv3wo zVq0${Os?I)BgcI>@hO#|DQfaUcl(u>=O4RE z{cv|^KJTmgdz5h5f16r+2JAMi0DGo#8&|ZNhAN**>P7rygULmgyjow>gnC)O%x$eF zbKp}fTw(5gdOZJ9Bj?Wlp5GlA`I9d`!aJ{#pAjc?TZ$GhhKedO652_vHT@x6tMcx+<+XmnSx;c8h`k^5sY-HmIOUoaO# zYTLoW`bUp^yL3%0=mVU-}S02vhwqnYIX;rtEjUtjoFlLGVEU!CUn!{lELi%<1KWcJW%TP}I9 z*?=+_YPMRE@}z1}UW|{!ieImZu zZ+fr;qP!1_qRaTlnac04Ds=hl&nWNzYLdTt$^ZDk`48dda%&a2>L2dkNoplA`utsq zp_K+&KuVIGn^*6)Ao-%~S4Dkt`U@JOEN39XMz5uYniTYJTz`C?hi?Kyx0B`to*)#I z@A(CtjLq1sx%yigwaN$AW}@0QVwzJE?Cp|#r;^`7S`RlM9XmO^D=T*AF{jbXlXJcz ze5EK}1dzme0h@};CZA_jkasW+1k3Ah%dI_TW_|hYvU02Av_*oRa8-u&m9Fz5FElJ( zEoWB}q7f&EK}XF=y%9dWB39UFpJ`1U(;kV8`A1KbdlwauJi7ET_P1pdByAvS0u#)3aZ8fJn@G+_eN=$=DjN@o^VO`bVL2vRnt3+?P+B*jCyPYZ4Ep2 zz#yxzuZ+#|!AP15u2MA)VN5#cs8ftmkS7kUdOs%ly;xT$L(J62~+&XB!nAYs%-GMhK2R4Pd{8llxwJ%^#LW+i!{)5cX=O~b`0acQ!gtU zcy*n%#7whi(0s}Ie%$rAmr40f(!r|O2Jlbn3+MO+)^;B%G_J#IA`_5Q8AWgTG^H2tdKDyned z_N1F1-n}A!k$?YIfwNDZEk0u`;%%Hk)I4v3!l+--X!Q<cui?xk=~^kQvaF zX;#~w>q)HF;v4WjkgbotmwB^ULJ6sJ^Nee-KjD;|zhDnM2;GDdwXuQsTWZLZeJ4seLun-k)R&X+xBiZ&Z&M%neHA zftSm-5AC-!)p~bY`yY`NBJ-E_8CPFhmku{NGcWc54#BL_8Som4F(lA8$@HSJ;Zu+= z$Iqu-Y@2rubG5{OxTb4Tt$W(b*-BmZL-VZpQvBcFf+mFeX9>IHB`KM!3ufLs#&}DB z(@qgUbP+hP0+h|`WC0Q{A)-{i3}K@HtvbBk=5D6GYAzgY5o4m^(w3x=VC!49Lj9p% z{EjL|$)BE((d%FL?&To3sDl`tDxkX_b>u z<(_|U{&nL^Yf5Q(87{L?@$v2__pe?n8JPTi&@#?g?B{!ApVpE7EfaQgp|)>Dj-{5O zW~~e9_viB^@O1fQLb5J-@EPGjexKVXKA$36Sv#*PP6uW>x9;qENm?T_3V*l)Qs^N@ zDCv(Q<{q~C(CIK0-#tf}6Sz5j&+8%aXDO#i%S5K8Al2sd#*XL8?A&&$AyCBCpuENO z(1=eTK2_Cb>7p(LM$Et+!NHzoHas>3-M)3=As`O#@>nftN*i<wIqb>VO74D zg+DM&HmwPx2?%~Ye-!xCSE@5D7k4kUT+sg*3VoMl9GfRP%}0M@?$#x3$pSE zA6_?%H~z9lbf&ddd}zP~FUC!8cFA`q^W3TRpW@tj?Z~%QhV9?$m@u_Vb>Cg>sV;jT zsEz`PB2A6+IL6(L^+2(i97G^VF#=(R6|Wf1G9H!85)O=%bAR-)K9yy!Z)~FB(TNEa z>}-_&!@17H4V9~bAbfeV+HPz73BUlrb^B~}U!crR$o1IN1^5OK=O0OBkYOoQ+kLN-ck359yhVy3L=ABo@ zB5tpe0j7+?J_dIJK#>3%a}@t6sLp5DbP%WoD>k?VK$N&dulHM88+mtBMnNoRUVeS( z5OzpxpE-N-siCkNH^jVVu_t$=%l4{WzLi(Irr0{B5#qmCIvm~zhs>-4;yQksH7O{R z$9b#H!X|P3#t1jQ&e#Df{uj)xd&%>dOGg`zf7|X2boE5nd>Gf4w4B#V)a|QsKO!ic z_{>r3%`=1Rvh#!x0_(Oo`%;$ppt5}!Ky@BQTrIdMbYMkZsmre%-_yEdt2Sx8csueK zNyw+>M}FX}V!wH^W>3kbPKMNvhEb~wZN}|}o#y9n%z9su^!Th?k^}}4+by_$!hrrA z=+Y2w8ch{nykvbg=go(lsIzqc=0gvx+W!J{=QjI`ZmAT2FoX8F?}J{THe`B!(LIa> z|DwC4s&u4{HUtt=Mm;02_}DtPWN{2O*p}yq4o%eQxwn{B8a}$Dv5RJSFX?tn_hCb) z>DQ2A#rJUVJ+uv}J+bgxVe+I^i^rMvICc&l*lzP1$a<_GAo-0=10{hu$sCFg++&b#d6 z!rjYc5~JU%xI5q?uXR0UmyL0dDGg8!)nG2A_}SGBDzisqNs;yPzAUAim%`pjH86ZQ zoiJwAa_;<*J9YX3GN)d1w$Mh?j};NKN8>x{%wyk8EbV9ZyoLZpMOKaeM2*LxdW^58 zxSLjuR?_n1dz>p=k!J}A`TA&6N-{B;oy%=M#@=P1ioifoG=o%yUP-l*pU&FRkGb5A zbsD@cNpJLkQN0&`X2gbE@VOQt?(?t&ZqdOn^xA^||7!2Mqng^*eS=a21ZmQnf{Ii{ ziUNX#B1VXy^riw*L#Wb1qDU_yumJ@Dl_oV(BOwH(3P|q>1Oke55=4k3#JBbx@0@eb z-gobP?;Ed-ao_nPW2}*t%rVzo-<9S_pLLHm&Vhn&Z85+Mk1pON`HaB--2mCt&mTT?^a=_`>MQBtbr zveVo;{QCPjItCP{Hc1fqeq%w%=6gJxs7i?+-QX?uA}Dw)WW4%THGS>GlbgLFzceWl za)TQdj4xbQDyqyUoe+!YXXL8ih<0@${sdKsS2auKHACv9_e&U}4k6bU+IJW-Ub*b* zdTUj~uyRF@(KEN}P?tH;>0wg6H;G zg+isnZ^58t%j3g@Uas~NSA3ob=Us~$W-+VHzrUY@J>@^k$B?EH-6+McxGSM0%Y&h%pHKI+GOPRds0A5E@!T5;bY(l{&d#T<*p{UKRGEoOPy)$JP&4{ILLZy3E*pAXA1 zaq5}C%+{Ewc9zp_FB7@a`;)Qm z%ncxvR8GeT{q%l?uACR9C6aE3e6@m;9C}?d9;m`i^z=|9=hW=9tx+1M^&f7$H<01( zv0>V}C^MJx1R>!FSEgiEFqFxC(U_2Em^Ar*KD2z63SZHjUzy>mwVPq*@BL&7omWf} z%FRi37MwxNBJfQrR<9w&J01nb<;H|w2F2*kN8$R>V8_ztEaIUbOezD$A)KzN(X46&PTlLYHa}PhWf<%WDx=#@`w@g}>zYlNW z5=~2s<6tJ**NHyE^_ak9^h8m%+hq1^(sm0s706X~WJjgjx{qsxuVfv$*wmruD|_Ei ziT~lshs!;04`%b#hhJ-EWFo zySUoptRE`5=-;!^Yw}>E)0BE=m8;a{Xkkmg zvs>Q0EG#Xl@KHyC(&a=JYK3aHV)EON!bG^~khk96yL?vXE~xr${jcI!XMP5PL2n+z-pmkr>fA)Er{L^Na6aKTMLNB zxfb5#GfNL*+cYF)hwr6cYBUH=Q~2oSr%+I5t_bf0G418C&mr9)_%2IodI|i>DBR<2 zvHQ5KK{ho@U&E|VY}#G*2Sa~2UZnP<(u-n`U0NvH z%lUT$oQP4|i!E*IM>=um8&j?fW8F%15WLlOBR*9yW#|pp^-TSE7q>i@5Wpdtp8isB zUD>wDxW&4|22Maeh^-Ha-N~bdlLGiWMPsVaC*ON!2|i$mjaDgpD?yA=$DYg-*4~Qw z@XmVcXbSlSl!{(JMq-8Tl4woqF2o}|k@$xZ96fYzrRcV5 znxP@Whr$*Oze?_1KzCH$`w6nA<`jAmm9i(yN0fEgN#zbcVqX%5&vR7}wrS`{{U9jL z*@$29VdNpWCJEKn=eFZVF=|EfuHb|yVpK=M2P=elQ_aY{*8WaxsM5Tn+;i`jmKnka z1*ym6l0^@0J^g;h^SaV9vdvgKtoRpL#LQY%D%7UFxkch0YWe<`rONQ)ftMRd_s!S` z489>9L!7i%uY^x<{YYgUjWeg5Ryv~VecDw3>g$r?6&n9#BgG5G`Pf1Q=?RGu4USU8 zngq>1f)zQetiL?<+}U5*dGwM$^hCoJed+!_0kNTP**}z2^LQc6epNKMQ;&u2kVQgN zzNDVLWjEqhH=;Iy8O>TZw=?E0^}EZg8-`tEwYr2lejvuA<-DW$H_~Q;&Mk`RNLOme zRjca3pv^>E!*UOgfV;=-yIj2r`@AQ1d7v}iC^_cP5908g$TSu$uiTD{%42ktT)CdM zrgF0Pc+zv670%GFCxl#;xV+P4C zsx!8nFs(xmFsX`hZ$jI|#RG|_sI)m4heo3K9u{BOU+=NAuR8)jY{#nu{Jb6_hTl$g zDE!butDMe!NAC$l z_p^h(qXen0|p;d0=52|4un%zbDx%0EROGlA@vD$Ji5vft~vwO@=7UABcp)t{oM zI^aVZPP-01$#wG!Jz4NY&Vx^mlsx(IT#ABN?}1m~1I#;mbyjUnKn4Ook!%z%Q%BxO z^gEGPbn=zg#iEYf9-d+%*u(6;O}r~7ugQjkM!AnYeU+R~I*BF?#I-Q18<8jCl`37v z=r)za?yAsp1MaZntf!R`eXzqCC`}?yv>4|v-O`V80Y=dn+_^>ytV4z8GAY^0Y-C#{ zAxtH4VZ?GUUOikaoHOtRp3UC$qv00|y>nOVP1g<kdv~%)A7Wt&>~O4EKdLUco~d!!qqS5 z;dRazuioKx=!(>H9{|CxPE-U&2w7pm`wZEA>c(-yFvXXn^C^-pnE?yC>=dd z20Jd%cFc{!^(0=RZ!tYAusr?5XW!{Up;zWak5tjC4Hv8*i}4l8FshXh#G@BETo(k z-jGD=+MzmaeLlz=#~U)y0#BI~BaA^|i!TBEEv;=tc;-^J z8U0??4PLg)VY6*iyLKE(1)tb-}IP-stu*e znyHEx#`$tzmKEo@w0b}KurGpfHtJ$d{xjO`ziXF+02-9&Mxg%o#{vpTy6^^&Q%KMw z`Gg=DA*-`gQ$S|vUe$kS8xV%z*Vvz+uTKCbvZ%#^pP;RDWKX(g|O!((^%JY6F1^oZt)3uYk;^~}oU1R;p z#jE2A)-wSwe?jvng-f52P zG3rkPg&flWOrB1eXd%Apa$3Z7(lYR=20y}G^69o|F#Qj^1F2}#W1_8J{ z&H%tpzjZkRtpu0>LSF*N-?V1G#m_*<&~xZ=f4?}8Pgfc^@)I;55e`UX^cnpGB>{i^ zZA(W3K0dj!ti27s@mnX@mp0k+DD3MM7_@=tb=9R2`*~2$y%KJgx1K{6H5VOVq)fpn*6{iF7 zSOBz&x{K^q+-Q2{;k{YS!yDd1$7vFuY`E0ig*UU$)*Jg6cQVPmD#iZMi;GFf`P-QO zV{i|-|LYI`WZwT8rT;krU;cMDjTM0A4)jN#n12+^eIIp1b`|~vZD?*)IX>i2NF%#- zq;SBmq9+!~#0m_?-Ku7J?;$$UfdUckl`p;N!Yq~XR25B5w+xz%10=_F)bFBJb~QzP zGQ!m>vHsIjrb%h`*HT++I&Z-*gz`e333=#g-~}7db_nf=eL#>Ph14=Lx-3@#;|b|9 zA~)~EyOt6o@-}U;G}inB?OQtELSe^l3W$SJn*`5Wa2Oviq&OwiwH%~+nNNIgLREW+ z266=i`F*L&v-ec(t7mfF24x?tOtzIX7e1gR>6uqw>A?^i_5oB27zFT$;=D%{40h7` zRgAibTkyRDZzPP*7vit42{sAIRj~o^B?%pgg=Bv&DF}8Hs;>P^ba9wqI|K_vW8?iA z*BN7n5g|8wth<`rT~C3MR+eW4uuA3dD`Rjjj|v0Lgt{h|rlyg|^X{*qg%TYP(qoe{ zm^1i}NweCIW{7^G&Ew=yfG!(Xt>SqgqboUy~z>&2R1)HZ5v z&I427vl;?1!j6W7&pp8`3Q@A+_v&@HD0TorqH;Z_iRAo_lHq$9d!WWQE2!8}KP5L! zSh?T{M5*B|w~&YYd+|~xr68yAEPC!f>-Oy4_-r=1^v|Hde}-dbQv1h=kd?YrJZcl~ zHVi!Ws)k?RiFerg%>MH;3lE-LVy-QqS5-C2Gs$23D4m!2cXi{ktX4N`x`^+_2aBKx z`^;0IBkN*$?gUF#tDS*3y`?L_o_y-x%36R_?`5FyMG$bs9%=nrM>27doV8O--t9ys zI-Vk@M6Xr(Y)1&0L^4$PK2}OJ6uM+v=d8VY8v3^U%6roai^=o$(TAtoTk5}0hXpcJ z0f$b5pZxj=AF@@AA+6QO82-lczE1Oa+Zyf0fzJRVh|{9C7`)W6d zrf}ATu>tG7HT=8I4DHv>AKBxn-=wquT0rzJUmP*A*AQP$H-d3d#}Ev;+Uazc@d+4($Hw(zx*cCbiAK46-Cs8GO${5J50VyM zqD}xc)ii>Gloh2J_1L+I3NBdL^3Wv8Xq6iwm~Vyh&vdxlk>45WYXpmo?R2j3%&`ue z`R3OG)zoC@kDBA7ulgI1Uy$A2!7T(`AoPF53Ajk_bAf}&v?azAg>Ckvnl}Ik#~-U9BpVqf5HS z>Gq>=y@h7Z_j!DSN?7oMgn562*~`%&wvn|;#n-Ne*&f5}lY*&3yn-6CnX+$0RO^ka zDpA>1NdMWdQz`WH9~W_q-0cm(yZ5F(W<)6gj@W@fpd77$=GHE?eavf?%3p%qa`0;a zO441zVx!e=*OIZ76#iQjW+DK3jxwG9cF)e!SK;D7PGEI|(y**YRIiAV*fHJ>Xh9wI z7UlkC=ib)@xXQc)w+a_<*r3{~vQ6_^2#3n@mtSmd=YKZuA>&)cy)=}u5G3>PT0LQJ zYI)W$FISxnNZ*ZD!s|`KmNfslFH*l9$JN|@U@7*@=SK9~>ff6mUI18f-|1)1ULI)^ zVQI`eZ@U!DyrQu@tGjLCgyqCcISqKPx^13>ot9bj>poA2d{4?VQI)eeW$K)(0)PP0A6snv&(R(o=fvOnemD%qmo!6kh!(O+YJ+6 z^_5ONx?sq6Ag9KL1Kr!?zN)JTw= zB)*`H>X@tX=w-_$4|WcrZp(jSCz#tmG2X@?N*(rlolLIiZkYtt<9vEI!@_di{^}i$ zABo0khs5i+ks=OuJj|ac6`J@bP$9eu94H`c$i{XlYKHbD4nWdKTT6%U z-s(NxarkWHrRgm#xo(h8xAXz8fr*{R6Lgh|l|8l;9WiGh9l&EiBB1y@0BSJk8=I9g z1g5VazFw?T694F^h|273xbz{1`H;VvNpr?e5KHi`k}Z)~^rm6h0cn}GJvO=g6ZG31 z={K7Iw(|%+t4j;^Az5sGHVz@~u7O~}R@aUx+g+#F?`G##7IkIC3J#R$r>U|F)Ud~b z))jq^IM25{!5vTU%sWM%ZJTAWqxNsMX5O4xg(Axvo-wBzy2gx8>`R)dtqV_IeU=*B z$@%38A^S5F40dE#68E$6CPw^^|48#&@%f8|EkIIp9|Z)_z;3#y*B*!eW|8PP0@Rx6 z4^~RMjjBu?^T<2P$Ext944wV;bJA(WFt<_q!TEfuDV&`&z!#CV=0p&M0u&;!bDy^0 zlbI$tZ#A7CoO|>lP~eBd=a$UwJs=OC&dBCO1^oo6H*vGB9#L_w<@&rtnSpH;HU1)VT>H>up=^vVyRca{aAuW^*++G7 z0>UxOQiGySBq=YQ9EdmDojN`>tajEDShQf1I!Qk)@&uuHRL5 z+f};mIgqjG!Z4YN*xVbP_~)I;=r{A@E0CY5gmdRJ)u|--Bi*_593JMLGl-cg9^LeL z=nFmeNYy1P&_}iLra<+bhi|J3;o)OCCgfA^89IYl-iQh>UFFEWifsjtsn-qR(KDFE zC4K#yhN_OvB1<6iPi4^J7g<|%`Q=kcr?QiKr)D&_>}s9=VhdQ#=hRhR(N(3yCc?$$ zow(abErL`JsIv0ix1-29#S(O*&0*EH3kgCx9mi|1*DgD19^f)qm`&Vk$fAh00dwH7 zj<&}7d& z;E+LYy2P6$%;7vao4Q<+?_lj_Et!VkCx+-p^hp9!!P)JQo?0L2t0V|s$mt#BNTd?h zdCnbssvzWxy}QsLP*&@j)2+!%n7wi*$*zZ7{!}J3%U{)}f4FtGfq{0)_M90*^TUBz zVS8##`caB#h7CDqSwcgi8;XqD;kupb5q1;&*`O{QBT!Omm`Nho^A4-^ashC z7P&YgyKN_sYwUotwnW>T_*3SFzhZXy?fw5Gyg!aH=%|CEMvzgK*dc5KMTurqxRiQr zlFw5}`51c5|LF9EIr%qYAN**@*ZP)X6!jG~xzfLIGJY5=5j^KuTOW!t@y}s+pZUh8Y zJLOvm--ErWF%eE(KS3f`vH9jO1*qW>LHGso8bg%5q;pvZv+z{?^m^EZyHIh&EpFpR zD0ZB!eV?C%XdyX?UnZxu8H~c&h1v+cx&BJr!e2(x_AcBBXFmx#DpZ#Epd)27@}bL8 z#_qbn=4OE2GR}*RQYacR@U={+AwU}KC^fYaJ~Jtg;Nc}yCr8ReV&!+3FkOq>8Pgyd zN|wdsJ=}|0E{RBG_IKyI909UnY3+@!H_Qr2d~;TA&uD=WTkfgHQfG7HVa7lt zw7xsrUhjl=A_>-p7CSEQ<>f5IjvRY8mTxwsuQ{~D(*-@2wz%jpSwEfg8k8#YoFiIV zcb0wR9-!I9CG??11ZzafWrI8ldLA^u=zWz3&64qZx;rMc-i&o1+UedaZwjlz(`|}F@{P!u&q=v%4r3L84w8h0 z`?!%6(deGbFrL$8AX}qjxA`u8{(igxr@o5drxH+}S`ClpX@O)!DoKIH70_v`=4Spj zz64W~rr>e-6u-3f36BCxv3pN9apewjJA!$AncJPa|8KZ8Ghn!P|z0r_U-;{H~=g(Vsu183t#* zmogtRunT5j)An^&m7`AFd7U6{C}3s)`mcOU{?6a3f-$fLmz z4G^?&QVt|{C%H!$@zhNJ;@D9<<{J+6l5*}+yUTO zs2}D}kz*4JvDfOjM2WC!2`5vq3r!&Ye!g;p?OplMV0M3|TY~M(r7P;QEOd8@W-R>d zf*vo`xz*~eJC5~$68Em{yAdgqvHNuj;r@e0&Z=q&Q5~YOX2PnEcDHnUUe{#kdYa}3 zX3dBg?ri+1`aW~g-mTXRQj5UUts{EI9Zf1zSoWV{Z)0F<-Q@ed?PyVr_%|zBEXh^r zp4s`&c9$CBR&E=MyYx7luk*2SKK}Mr1eLcz2bU~6RqrP29)ze}ogeGlDJRiX*gu_( zcranL)y*<`^Tj#BGgq6W)n{WC@!qeF?n<_h6!iE!^Q3TqV4FsK*u)OGo#dQ$>+sXZ z(w)}wpFSUc)Wr6JgHXAuZtMR`W?J(^I@*!8PZKe37VbPt)Cm4&wM_6qf71=wukr5B zrD@sNo?~-Y-{jV}K70^uQ75u5FBONA8D{Vy#`mO>;SNX`;PM>ulH|_6Y!Ytf$CV^B zL{w^RQ(NECA2#g26?(H%1C-toA!ZYkr%JCW7aY&7p!TbgXKPCP$1;#1dA-7tFMV~<_8A_vh6)O6D5#O=lAbdp;V z{9+|Mfck;ruLQdhOTsLNnI^Kue|dLpo7M>JYn#57#nPbTKEd0yc(CrRE1SI6a&`wL zKUzsAh-6~dHnBB*^=>Jlxv1Cno$+DQGb>^MQ*efCK&0>G52d!UEg7;nGqVX?)_VDt z8ti$~_h2NIKQmt&o|QWwzK@yITdQ0+X)Xe`<}td;$c5QYtjk0c7|<@kbyMawDuDsX zYO}6O`~k%pDnH3UTPq3MJs6X5$s7rKmk}vj&E8N`{ZzSU?-7q-LfM(JGoZE8qw8f6 zImj?H3G=P`G|n<_lfFq^qvz;pR>76Lf(ob#4j6Dw{zHZsH6AJIS=~Cm8vfeBI!ZGb zCi?1Ky{3|)zkP30e|+NgVTE((L1eABqbP8$x=G=7ibCB5I1R&TDiBK(=8~P$is$_6S7(k%pb0Anw?Qbf%z` zg_3n~Af*U5E=g;jW7<#m=nEH@JT{EABC(Bao0tw*4_B?{fy38z1M}Fkn0<_{Sj1fZ zEQ;4jx!yr`imCwA5TV*v-lm1FuPqS1&YTY|_6O^vodF3wP;7t5YCXr);d(w`cn3LS zM$16$BTg7>_2vK~9A7)eHHG|;AGB~>`hz~?`mP;)gj|y#FHuZMrf^iGGBu-NJEoE9yq%I}Ws)lYzUM!fa&%Ze)gNyJt8he?iiLOn&m0Fnnz@0gE zZPCrT`$}2N6|rr}1iZihi(*Wp9!{qrVt6KWMJ~Kdp$5E>rM~Yt@bL%4k(xmoz>6(N zePE>`OYNw+aP^?zc_r^j(kwV`(uCR9-X-OD=!s`?F(xP)T9zxOQ4b&^;n$I(K+MT( z@z{f*Z@`q!E{B?!-Va*QZ398YDleRILKw5qroXmnqx@KYpH->iiBJe^-zw@drNZL|f5!_7?N&wY8}hM)D%Qr!>wHf2rkvC%!cqE~Gc1;w7A z$O9S47VgId0|iuP6Ux|Px!z8@qkifYwHQpAqT)xUqz?`1%%le{5o{!6{GQ6%cS^v5 zc#D8K7{WO)ud=p}G)Y_f;kT0Kn0r|04Bjoi*!Ujd^D9*;RaK$G?0Y>4#DbkCFdwhk zZf)q)j6$ z!%`!wIaE!#*^Vxc#m^(zZK!D430ToPo@IQLR$3cpv~f}5$+M?K`NxCcmh)@^?~UA%B~T;54z6iV%)Z0UsW)cpk6k)0SlrYZDdloqu)cy0>m z;dHc(lGTnRM}~O7&v_k*Q9n9LxGb7*?iy@los9LjSG^Fs&s!*Wu>8jj(-j(PLML%k zB?k$=jRgM$WiGxT?rNqv1-@vplRQE@-(8`%R_=o7&)mLVnFInQ7mgy1_9gG8AjtM)vg z9w`gcSOccnKy4TMBKvp($zpl?rbWd zW=U3fhUICTkE=>OV8(>$J_5RZy~SYzu1%RI&hC^^kVzW|Vd7Ls%Z*`#@T!)!Cq^gH z52{-bLdFXE^%oX&*BtotlAd?Zr<3BKQBRR-o2@$)j{vzla*ir}k8rv=agV~K9PaYqBUUV(WpXEMuQutO1O768_iI;aaQvI|sLUp|c{rntu1h=lf<(K3{ zlF*rThy-Z&?*1obNPjCqI#H4M?-^8WxBu**?7w>N&&hhYzS6@Wj0L3pm!&@zoB(*) z|4@wLkM5oPhXcI0p~G7O@l!0-t#n;%x;A9(rJ4D5!#VS=xOv%uPhdV!FQ2LL$ppCr zdeqB`$fXnWD)iF;Tt?4`E}f~j%|{Vp2>gnDk^)Ya^+?PBWzfs4xE69DfUwz@B1c;P z1Py}Qov7vj{0adSr2$I}Ul$|N@i^dJr~eA1*+#aqI|E`@D!fRN@voSzJ-L?$89ZRA zJ@$}9V3L^_0dg8cfcJ7DWuF-f0P3Sp769eaz<3<_SAYIBKL4_x|A+HyaEPww_F5!w zdb&@Ipr0j#_Mf@Y(}>5pRP@ye-V-{{^6XLOh2cMeocs|K<> 8) | \ - ((((uint32_t)(n) & 0xFF000000)) >> 24)) - -#ifdef CS_CACHEEX_AIO -void camd35_cacheex_feature_trigger_in(struct s_client *cl, uint8_t *buf) -{ - int32_t feature = 0; - uint16_t i = 20; - uint8_t filter_count; - uint8_t j, k, l, rc; - feature = buf[21] | (buf[20] << 8); - FTAB *lgonly_tab; - - // check client & cacheex-mode - if( - !check_client(cl) || - !( - (cl->typ == 'c' && cl->account->cacheex.mode > 0) || - (cl->typ == 'p' && cl->reader->cacheex.mode > 0) - ) - ) - { - return; - } - - switch(feature) - { - // set localgenerated only - case 1: - if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1)) - { - if(cfg.cacheex_lg_only_remote_settings || cl->account->cacheex.lg_only_remote_settings) - cl->account->cacheex.localgenerated_only = buf[24]; - else if(buf[24]) - cl->account->cacheex.localgenerated_only = buf[24]; - } - else if(cl->typ == 'p' && cl->reader->cacheex.mode == 3) - { - if(cfg.cacheex_lg_only_remote_settings || cl->reader->cacheex.lg_only_remote_settings) - cl->reader->cacheex.localgenerated_only = buf[24]; - else if(buf[24]) - cl->reader->cacheex.localgenerated_only = buf[24]; - } - break; - // set localgenerated only caidtab - case 2: - filter_count = buf[i+4]; - i += 5; - - memset(&lgonly_tab, 0, sizeof(lgonly_tab)); - - if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1)) - { - lgonly_tab = &cl->account->cacheex.lg_only_tab; - } - else if(cl->typ == 'p' && cl->reader->cacheex.mode == 3) - { - lgonly_tab = &cl->reader->cacheex.lg_only_tab; - } - else - { - return; - } - - // remotesettings enabled - replace local settings - if(cfg.cacheex_lg_only_remote_settings || - ( - (cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1) && cl->account->cacheex.lg_only_remote_settings) - || (cl->typ == 'p' && cl->reader->cacheex.mode == 3 && cl->reader->cacheex.lg_only_remote_settings) - ) - ) - { - ftab_clear(lgonly_tab); - - for(j = 0; j < filter_count; j++) - { - FILTER d; - memset(&d, 0, sizeof(d)); - - d.caid = b2i(2, buf + i); - i += 2; - - d.nprids = 1; - d.prids[0] = NO_PROVID_VALUE; - - ftab_add(lgonly_tab, &d); - } - } - // remotesettings disabled - write additional remote-caids received - else - { - for(j = 0; j < filter_count; j++) - { - FILTER d; - memset(&d, 0, sizeof(d)); - - d.caid = b2i(2, buf + i); - i += 2; - - d.nprids = 1; - d.prids[0] = NO_PROVID_VALUE; - - if(!chk_lg_only_cp(d.caid, d.prids[0], lgonly_tab)) - { - cs_log_dbg(D_CACHEEX, "%04X:%06X not found in local settings - adding them", d.caid, d.prids[0]); - - for(l = rc = 0; (!rc) && (l < lgonly_tab->nfilts); l++) - { - if(lgonly_tab->filts[l].caid == d.caid) - { - rc = 1; - - if(lgonly_tab->filts[l].nprids+1 <= CS_MAXPROV) - { - lgonly_tab->filts[l].prids[lgonly_tab->filts[l].nprids] = d.prids[0]; - lgonly_tab->filts[l].nprids++; - } - else - { - cs_log_dbg(D_CACHEEX, "error: cacheex_lg_only_tab -> max. number(%i) of providers reached", CS_MAXPROV); - } - } - } - if(!rc) - { - ftab_add(lgonly_tab, &d); - } - } - } - } - break; - // set cacheex_ecm_filter - extended - case 4: - filter_count = buf[i+4]; - i += 5; - - CECSPVALUETAB *filter; - memset(&filter, 0, sizeof(filter)); - - if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1) && cl->account->cacheex.allow_filter) - { - filter = &cl->account->cacheex.filter_caidtab; - } - else if(cl->typ == 'p' && cl->reader->cacheex.mode == 3 && cl->reader->cacheex.allow_filter) - { - filter = &cl->reader->cacheex.filter_caidtab; - } - else - { - return; - } - - cecspvaluetab_clear(filter); - - for(j = 0; j < filter_count; j++) - { - int32_t caid = -1, cmask = -1, provid = -1, srvid = -1; - CECSPVALUETAB_DATA d; - memset(&d, 0, sizeof(d)); - - caid = b2i(2, buf + i); - if(caid == 0xFFFF) caid = -1; - i += 2; - - cmask = b2i(2, buf + i); - if(cmask == 0xFFFF) cmask = -1; - i += 2; - - provid = b2i(3, buf + i); - if(provid == 0xFFFFFF) provid = -1; - i += 3; - - srvid = b2i(2, buf + i); - if(srvid == 0xFFFF) srvid = -1; - i += 2; - - if(caid > 0) - { - d.caid = caid; - d.cmask = cmask; - d.prid = provid; - d.srvid = srvid; - cecspvaluetab_add(filter, &d); - } - } - break; - // no push after - case 8: ; - CAIDVALUETAB *ctab; - memset(&ctab, 0, sizeof(ctab)); - - if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1)) - { - ctab = &cl->account->cacheex.cacheex_nopushafter_tab; - } - else if(cl->typ == 'p' && cl->reader->cacheex.mode == 3) - { - ctab = &cl->reader->cacheex.cacheex_nopushafter_tab; - } - else - { - return; - } - - filter_count = buf[i+4]; - i += 5; - - caidvaluetab_clear(ctab); - - for(j = 0; j < filter_count; j++) - { - uint16_t caid = 0, value = 0; - CAIDVALUETAB_DATA d; - memset(&d, 0, sizeof(d)); - - caid = b2i(2, buf + i); - if(caid == 0xFFFF) caid = -1; - i += 2; - - value = b2i(2, buf + i); - if(value == 0xFFFF) value = -1; - i += 2; - - if(caid > 0) - { - d.caid = caid; - d.value = value; - caidvaluetab_add(ctab, &d); - } - } - break; - // max hop - case 16: - if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1) && cl->account->cacheex.allow_maxhop) - { - cl->account->cacheex.maxhop = buf[24]; - cl->account->cacheex.maxhop_lg = buf[25]; - } - else if(cl->typ == 'p' && cl->reader->cacheex.mode == 3 && cl->reader->cacheex.allow_maxhop) - { - cl->reader->cacheex.maxhop = buf[24]; - cl->reader->cacheex.maxhop_lg = buf[25]; - } - break; - // aio-version - case 32: ; - uint16_t payload_size = b2i(2, buf + i + 2); - if(cl->typ == 'c' && cl->account->cacheex.mode > 0) - { - char *ofs = (char *)buf + i + 4; - memset(cl->account->cacheex.aio_version, 0, sizeof(cl->account->cacheex.aio_version)); - if(payload_size > 0) - { - size_t str_len = strnlen(ofs, payload_size); - if(str_len >= sizeof(cl->account->cacheex.aio_version)) - str_len = sizeof(cl->account->cacheex.aio_version) - 1; - memcpy(cl->account->cacheex.aio_version, ofs, str_len); - // sanitize: remove non-printable characters - size_t x; - for(x = 0; x < str_len; x++) - { - if(cl->account->cacheex.aio_version[x] < 0x20 || cl->account->cacheex.aio_version[x] > 0x7E) - { - cl->account->cacheex.aio_version[x] = '\0'; - break; - } - } - } - } - else if(cl->typ == 'p' && cl->reader->cacheex.mode > 0) - { - char *ofs = (char *)buf + i + 4; - memset(cl->reader->cacheex.aio_version, 0, sizeof(cl->reader->cacheex.aio_version)); - if(payload_size > 0) - { - size_t str_len = strnlen(ofs, payload_size); - if(str_len >= sizeof(cl->reader->cacheex.aio_version)) - str_len = sizeof(cl->reader->cacheex.aio_version) - 1; - memcpy(cl->reader->cacheex.aio_version, ofs, str_len); - // sanitize: remove non-printable characters - size_t x; - for(x = 0; x < str_len; x++) - { - if(cl->reader->cacheex.aio_version[x] < 0x20 || cl->reader->cacheex.aio_version[x] > 0x7E) - { - cl->reader->cacheex.aio_version[x] = '\0'; - break; - } - } - } - } - break; - // lg_only_tab caid:prov1[,provN][;caid:prov] - case 64: ; - memset(&lgonly_tab, 0, sizeof(lgonly_tab)); - - if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1)) - { - lgonly_tab = &cl->account->cacheex.lg_only_tab; - } - else if(cl->typ == 'p' && cl->reader->cacheex.mode == 3) - { - lgonly_tab = &cl->reader->cacheex.lg_only_tab; - } - else - { - return; - } - - filter_count = buf[i+4]; - i += 5; - - // remotesettings enabled - replace local settings - if(cfg.cacheex_lg_only_remote_settings || - ( - (cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1) && cl->account->cacheex.lg_only_remote_settings) - || (cl->typ == 'p' && cl->reader->cacheex.mode == 3 && cl->reader->cacheex.lg_only_remote_settings) - || !lgonly_tab->nfilts - ) - ) - { - ftab_clear(lgonly_tab); - - for(j = 0; j < filter_count; j++) - { - FILTER d; - memset(&d, 0, sizeof(d)); - - d.caid = b2i(2, buf + i); - i += 2; - - d.nprids = b2i(1, buf + i); - i += 1; - - for(k=0; k < d.nprids; k++) - { - d.prids[k] = b2i(3, buf + i); - i += 3; - } - ftab_add(lgonly_tab, &d); - - } - } - // remotesettings disabled - write additional remote-caid/provids received - else - { - for(j = 0; j < filter_count; j++) - { - FILTER d; - memset(&d, 0, sizeof(d)); - - d.caid = b2i(2, buf + i); - i += 2; - - d.nprids = b2i(1, buf + i); - i += 1; - - for(k=0; k < d.nprids; k++) - { - d.prids[k] = b2i(3, buf + i); - i += 3; - - if(!chk_ident_filter(d.caid, d.prids[k], lgonly_tab)) - { - cs_log_dbg(D_CACHEEX, "%04X:%06X not found in local settings - adding them", d.caid, d.prids[k]); - - for(l = rc = 0; (!rc) && (l < lgonly_tab->nfilts); l++) - { - if(lgonly_tab->filts[l].caid == d.caid) - { - rc = 1; - - if(lgonly_tab->filts[l].nprids+1 <= CS_MAXPROV) - { - lgonly_tab->filts[l].prids[lgonly_tab->filts[l].nprids] = d.prids[k]; - lgonly_tab->filts[l].nprids++; - } - else - { - cs_log_dbg(D_CACHEEX, "error: cacheex_lg_only_tab -> max. number of providers reached"); - } - } - } - if(!rc) - { - ftab_add(lgonly_tab, &d); - } - } - } - } - } - break; - default: - return; - } -} - -void camd35_cacheex_feature_trigger(struct s_client *cl, int32_t feature, uint8_t mode) -{ - // size: 20 + (feature-bitfield & mask: 2) + payload-size: 2 + feature-payload :x - uint16_t size = 20 + 2 + 2; - int i = 0; - uint8_t j; - uint8_t payload[MAX_ECM_SIZE-size]; - memset(payload, 0, sizeof(payload)); - - // check client & cacheex-mode - if(!check_client(cl)) - { - return; - } - - switch(feature) - { - FTAB *lgonly_tab; - // set localgenerated only - case 1: - size += 1; - if(size < 32) - size = 32; - - // bitfield - i2b_buf(2, feature, payload + i); - i += 2; - // payload-size - i2b_buf(2, 1, payload + i); - i += 2; - // set payload - if(mode == 2) - { - if(cl->reader->cacheex.localgenerated_only_in) - payload[i] = cl->reader->cacheex.localgenerated_only_in; - else - payload[i] = cfg.cacheex_localgenerated_only_in; - } - else if(mode == 3) - { - if(cl->account->cacheex.localgenerated_only_in) - payload[i] = cl->account->cacheex.localgenerated_only_in; - else - payload[i] = cfg.cacheex_localgenerated_only_in; - } - - break; - // set localgenerated only caidtab; cx-aio < 9.2.6-04 - case 2: ; - if(mode == 2) - { - lgonly_tab = &cl->reader->cacheex.lg_only_in_tab; - if(!lgonly_tab->nfilts) - lgonly_tab = &cfg.cacheex_lg_only_in_tab; - } - else if(mode == 3) - { - lgonly_tab = &cl->account->cacheex.lg_only_in_tab; - if(!lgonly_tab->nfilts) - lgonly_tab = &cfg.cacheex_lg_only_in_tab; - } - else - { - return; - } - - size += (lgonly_tab->nfilts * 2 + 1); - if(size < 32) - size = 32; - - // bitfield - i2b_buf(2, feature, payload + i); - i += 2; - // payload-size - if((lgonly_tab->nfilts * 2 + 1) > (int)sizeof(payload)) - { - cs_log_dbg(D_CACHEEX, "ERROR: too much localgenerated only caidtab-entries (max. 255)"); - return; - } - i2b_buf(2, (lgonly_tab->nfilts * 2 + 1), payload + i); // n * caid + ctnum - i += 2; - // set payload - if(lgonly_tab->nfilts > 255) - { - cs_log_dbg(D_CACHEEX, "ERROR: too much localgenerated only caidtab-entries (max. 255)"); - return; - } - payload[i] = lgonly_tab->nfilts; - i += 1; - - for(j = 0; j < lgonly_tab->nfilts; j++) - { - FILTER *d = &lgonly_tab->filts[j]; - if(d->caid) - { - i2b_buf(2, d->caid, payload + i); - i += 2; - } - else - { - continue; - } - } - break; - // cacchex_ecm_filter extendend - case 4: ; - CECSPVALUETAB *filter; - if(mode == 2) - { - filter = &cl->reader->cacheex.filter_caidtab; - // if not set, use global settings - if(cl->reader->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab.cevnum > 0) - filter = &cfg.cacheex_filter_caidtab; - // if aio, use global aio settings - if(cl->reader->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab_aio.cevnum > 0 && cl->cacheex_aio_checked && (cl->reader->cacheex.feature_bitfield & 4)) - filter = &cfg.cacheex_filter_caidtab_aio; - } - else if(mode == 3) - { - - filter = &cl->account->cacheex.filter_caidtab; - // if not set, use global settings - if(cl->account->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab.cevnum > 0) - filter = &cfg.cacheex_filter_caidtab; - if(cl->account->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab_aio.cevnum > 0 && cl->cacheex_aio_checked && (cl->account->cacheex.feature_bitfield & 4)) - filter = &cfg.cacheex_filter_caidtab_aio; - } - else - { - return; - } - - size += (filter->cevnum * 9 + 1); - if(size < 32) - size = 32; - - // bitfield - i2b_buf(2, feature, payload + i); - i += 2; - // payload-size - if((filter->cevnum * 9 + 1) > (int)sizeof(payload)) - { - cs_log_dbg(D_CACHEEX, "ERROR: to much cacheex_ecm_filter-entries (max. 63), only 15 default camd3-filters sent"); - return; - } - i2b_buf(2, (filter->cevnum * 9 + 1), payload + i); // n * (caid2,mask2,provid3,srvid2) + ctnum1 - i += 2; - // set payload - payload[i] = filter->cevnum; - i += 1; - - for(j = 0; j < filter->cevnum; j++) - { - CECSPVALUETAB_DATA *d = &filter->cevdata[j]; - if(d->caid) - { - i2b_buf(2, d->caid, payload + i); - i += 2; - } - if(d->cmask) - { - i2b_buf(2, d->cmask, payload + i); - } - i += 2; - - if(d->prid) - { - i2b_buf(3, d->prid, payload + i); - } - i += 3; - - if(d->srvid) - { - i2b_buf(2, d->srvid, payload + i); - } - i += 2; - } - - camd35_cacheex_send_push_filter(cl, 2); - break; - // no push after - case 8: ; - CAIDVALUETAB *ctab; - if(mode == 2) - { - ctab = &cl->reader->cacheex.cacheex_nopushafter_tab; - if(!ctab->cvnum) - ctab = &cfg.cacheex_nopushafter_tab; - } - else if(mode == 3) - { - ctab = &cl->account->cacheex.cacheex_nopushafter_tab; - if(!ctab->cvnum) - ctab = &cfg.cacheex_nopushafter_tab; - } - else - { - return; - } - - size += (ctab->cvnum * 4 + 1); - if(size < 32) - size = 32; - - // bitfield - i2b_buf(2, feature, payload + i); - i += 2; - // payload-size - if((ctab->cvnum * 4 + 1) > (int)sizeof(payload)) - { - cs_log_dbg(D_CACHEEX, "ERROR: to much no push after caidtvalueab-entries (max. 255)"); - return; - } - i2b_buf(2, (ctab->cvnum * 4 + 1), payload + i); // n * (caid2+value2) + cvnum - i += 2; - // set payload - if(ctab->cvnum > 255) - { - cs_log_dbg(D_CACHEEX, "ERROR: to much no push after caidtvalueab-entries (max. 255)"); - return; - } - payload[i] = ctab->cvnum; - i += 1; - - for(j = 0; j < ctab->cvnum; j++) - { - CAIDVALUETAB_DATA *d = &ctab->cvdata[j]; - if(d->caid) - { - i2b_buf(2, d->caid, payload + i); - i += 2; - i2b_buf(2, d->value, payload + i); - i += 2; - } - else - { - continue; - } - } - break; - // maxhop - case 16: - size += 2; - if(size < 32) - size = 32; - - // bitfield - i2b_buf(2, feature, payload + i); - i += 2; - // payload-size - i2b_buf(2, 2, payload + i); - i += 2; - // set payload - if(mode == 2) - { - if(cl->reader->cacheex.maxhop) - payload[i] = cl->reader->cacheex.maxhop; - else - payload[i] = 0; - i += 1; - - if(cl->reader->cacheex.maxhop_lg) - payload[i] = cl->reader->cacheex.maxhop_lg; - else - payload[i] = 0; - } - else if(mode == 3) - { - if(cl->account->cacheex.maxhop) - payload[i] = cl->account->cacheex.maxhop; - else - payload[i] = 0; - i += 1; - - if(cl->account->cacheex.maxhop_lg) - payload[i] = cl->account->cacheex.maxhop_lg; - else - payload[i] = 0; - } - break; - // aio-version - case 32: ; - size += CS_AIO_VERSION_LEN; - if(size < 32) - size = 32; - - uint8_t token[CS_AIO_VERSION_LEN]; - memset(token, 0, sizeof(token)); - - // bitfield - i2b_buf(2, feature, payload + i); - i += 2; - // payload-size - i2b_buf(2, sizeof(token), payload + i); - i += 2; - // set payload - - snprintf((char *)token, sizeof(token), "%s", CS_AIO_VERSION); - uint8_t *ofs = payload + i; - memcpy(ofs, token, sizeof(token)); - break; - // lg_only_tab - case 64: ; - // bitfield - i2b_buf(2, feature, payload + i); - i += 2; - - if(mode == 2) - { - lgonly_tab = &cl->reader->cacheex.lg_only_in_tab; - if(!lgonly_tab->nfilts) - lgonly_tab = &cfg.cacheex_lg_only_in_tab; - } - else if(mode == 3) - { - lgonly_tab = &cl->account->cacheex.lg_only_in_tab; - if(!lgonly_tab->nfilts) - lgonly_tab = &cfg.cacheex_lg_only_in_tab; - } - else - { - return; - } - - char *cx_aio_ftab; - cx_aio_ftab = cxaio_ftab_to_buf(lgonly_tab); - if(cs_strlen(cx_aio_ftab) > 0 && cx_aio_ftab[0] != '\0') - { - size += cs_strlen(cx_aio_ftab) * sizeof(char); - - // payload-size - i2b_buf(2, cs_strlen(cx_aio_ftab), payload + i); - i += 2; - - // filter counter - payload[i] = lgonly_tab->nfilts; - i += 1; - - for(j=0; j> 8; - - uint8_t *ofs = buf + 20; - memcpy(ofs, payload, size - 20); - - camd35_send_without_timeout(cl, buf, size-20); // send adds +20 -} - -void camd35_cacheex_feature_request_save(struct s_client *cl, uint8_t *buf) -{ - int32_t field = b2i(2, (buf+20)); - - if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1)) - { - cl->account->cacheex.feature_bitfield = field; - // flag 32 => aio-version - if(cl->account->cacheex.feature_bitfield & 32) - { - camd35_cacheex_feature_trigger(cl, 32, 2); - } - } - - if(cl->typ == 'p' && cl->reader->cacheex.mode == 3) - { - cl->reader->cacheex.feature_bitfield = field; - // flag 32 => aio-version - if(cl->reader->cacheex.feature_bitfield & 32) - { - camd35_cacheex_feature_trigger(cl, 32, 3); - } - } - - if(cl->typ == 'c' && cl->account->cacheex.mode == 3) - { - struct s_auth *acc = cl->account; - if(acc) - { - acc->cacheex.feature_bitfield = field; - // process feature-specific actions based on feature_bitfield received - - // flag 1 => set localgenerated only flag - if(acc->cacheex.feature_bitfield & 1) - { - camd35_cacheex_feature_trigger(cl, 1, 3); - } - // flag 2 => set localgenerated only caids flag - if(acc->cacheex.feature_bitfield & 2 && !(acc->cacheex.feature_bitfield & 64)) - { - camd35_cacheex_feature_trigger(cl, 2, 3); - } - // flag 4 => set cacheex_ecm_filter (extended) - if(acc->cacheex.feature_bitfield & 4) - { - camd35_cacheex_feature_trigger(cl, 4, 3); - } - // flag 8 => np push after caids - if(acc->cacheex.feature_bitfield & 8) - { - camd35_cacheex_feature_trigger(cl, 8, 3); - } - // flag 16 => maxhop - if(acc->cacheex.feature_bitfield & 16) - { - camd35_cacheex_feature_trigger(cl, 16, 3); - } - // flag 32 => aio-version - if(acc->cacheex.feature_bitfield & 32) - { - camd35_cacheex_feature_trigger(cl, 32, 3); - } - // flag 64 => lg_only_tab - if(acc->cacheex.feature_bitfield & 64) - { - camd35_cacheex_feature_trigger(cl, 64, 3); - } - } - else - { - cs_log_dbg(D_CACHEEX, "feature_bitfield save failed - cl, %s", username(cl)); - } - } - else if(cl->typ == 'p' && (cl->reader->cacheex.mode == 2 || cl->reader->cacheex.mode == 1)) - { - struct s_reader *rdr = cl->reader; - if(rdr) - { - rdr->cacheex.feature_bitfield = field; - // process feature-specific actions - - // flag 1 => set localgenerated_only; cause of rdr->cacheex.localgenerated_only_in is set - if(rdr->cacheex.feature_bitfield & 1) - { - camd35_cacheex_feature_trigger(cl, 1, 2); - } - - // flag 2 => set lg_only_tab; cause of rdr->cacheex.lg_only_in_tab is set - if(rdr->cacheex.feature_bitfield & 2 && !(rdr->cacheex.feature_bitfield & 64)) - { - camd35_cacheex_feature_trigger(cl, 2, 2); - } - - // flag 4 => set cacheex_ecm_filter (extended) - if(rdr->cacheex.feature_bitfield & 4) - { - camd35_cacheex_feature_trigger(cl, 4, 2); - } - - // flag 8 => no push after caids - if(rdr->cacheex.feature_bitfield & 8) - { - camd35_cacheex_feature_trigger(cl, 8, 2); - } - // flag 16 => maxhop - if(rdr->cacheex.feature_bitfield & 16) - { - camd35_cacheex_feature_trigger(cl, 16, 2); - } - // flag 32 => aio-version - if(rdr->cacheex.feature_bitfield & 32) - { - camd35_cacheex_feature_trigger(cl, 32, 2); - } - // flag 64 => lg_only_tab - if(rdr->cacheex.feature_bitfield & 64) - { - camd35_cacheex_feature_trigger(cl, 64, 2); - } - } - else - { - cs_log_dbg(D_CACHEEX, "feature_bitfield save failed - rdr, %s", username(cl)); - } - } -} - -void camd35_cacheex_feature_request(struct s_client *cl) -{ - int i = 20; - - uint8_t buf[32]; - memset(buf, 0, sizeof(buf)); - buf[0] = 0x40; - buf[1] = 12; - buf[2] = 0; - - i2b_buf(2, CACHEEX_FEATURES, buf + i); // set feature-list here - - camd35_send_without_timeout(cl, buf, 12); // send adds +20 -} - -void camd35_cacheex_feature_request_reply(struct s_client *cl, uint8_t *buf) -{ - camd35_cacheex_feature_request_save(cl, buf); - int i = 20; - - uint8_t rbuf[32]; - memset(rbuf, 0, sizeof(rbuf)); - rbuf[0] = 0x41; - rbuf[1] = 12; - rbuf[2] = 0; - - i2b_buf(2, CACHEEX_FEATURES, rbuf + i); - - camd35_send_without_timeout(cl, rbuf, 12); // send adds +20 -} -#endif - - -/** - * send push filter - */ -void camd35_cacheex_send_push_filter(struct s_client *cl, uint8_t mode) -{ - struct s_reader *rdr = cl->reader; - int i = 20, j; - CECSPVALUETAB *filter; - // maximum size: 20+255 - uint8_t buf[20+242]; - memset(buf, 0, sizeof(buf)); - buf[0] = 0x3c; - buf[1] = 0xf2; - - // mode==2 send filters from rdr - if(mode == 2 && rdr) - { - filter = &rdr->cacheex.filter_caidtab; -#ifdef CS_CACHEEX_AIO - // if not set, use global settings - if(rdr->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab.cevnum > 0) - filter = &cfg.cacheex_filter_caidtab; -#endif - } - // mode==3 send filters from acc - else if(mode == 3 && cl->typ == 'c' && cl->account) - { - filter = &cl->account->cacheex.filter_caidtab; -#ifdef CS_CACHEEX_AIO - // if not set, use global settings - if(cl->account->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab.cevnum > 0) - filter = &cfg.cacheex_filter_caidtab; -#endif - } - else { - return; - } - - i2b_buf(2, filter->cevnum, buf + i); - i += 2; - - int32_t max_filters = 15; - for(j=0; jcevnum > j){ - CECSPVALUETAB_DATA *d = &filter->cevdata[j]; - i2b_buf(4, d->caid, buf + i); - } - i += 4; - } - - for(j=0; jcevnum > j){ - CECSPVALUETAB_DATA *d = &filter->cevdata[j]; - i2b_buf(4, d->cmask, buf + i); - } - i += 4; - } - - for(j=0; jcevnum > j){ - CECSPVALUETAB_DATA *d = &filter->cevdata[j]; - i2b_buf(4, d->prid, buf + i); - } - i += 4; - } - - for(j=0; jcevnum > j){ - CECSPVALUETAB_DATA *d = &filter->cevdata[j]; - i2b_buf(4, d->srvid, buf + i); - } - i += 4; - } - - cs_log_dbg(D_CACHEEX, "cacheex: sending push filter request to %s", username(cl)); - camd35_send_without_timeout(cl, buf, 242); // send adds +20 -} - -/** - * store received push filter - */ -static void camd35_cacheex_push_filter(struct s_client *cl, uint8_t *buf, uint8_t mode) -{ - struct s_reader *rdr = cl->reader; - int i = 20, j; - int32_t caid, cmask, provid, srvid; - CECSPVALUETAB *filter; - - // mode==2 write filters to acc - if(mode == 2 && cl->typ == 'c' && cl->account && cl->account->cacheex.mode == 2 - && cl->account->cacheex.allow_filter == 1) - { - filter = &cl->account->cacheex.filter_caidtab; - } - // mode==3 write filters to rdr - else if(mode == 3 && rdr && rdr->cacheex.allow_filter == 1) - { - filter = &rdr->cacheex.filter_caidtab; - } - else { - return; - } - - cecspvaluetab_clear(filter); - i += 2; - - int32_t max_filters = 15; - for(j=0; j 0){ - CECSPVALUETAB_DATA d; - memset(&d, 0, sizeof(d)); - d.caid = b2i(4, buf + i); - cecspvaluetab_add(filter, &d); - } - i += 4; - } - - for(j=0; jcevnum){ - CECSPVALUETAB_DATA *d = &filter->cevdata[j]; - d->cmask = cmask; - } - i += 4; - } - - for(j=0; jcevnum){ - CECSPVALUETAB_DATA *d = &filter->cevdata[j]; - d->prid = provid; - } - i += 4; - } - - for(j=0; jcevnum){ - CECSPVALUETAB_DATA *d = &filter->cevdata[j]; - d->srvid = srvid; - } - i += 4; - } - - cs_log_dbg(D_CACHEEX, "cacheex: received push filter request from %s", username(cl)); -} - -static int32_t camd35_cacheex_push_chk(struct s_client *cl, ECM_REQUEST *er) -{ - if( - ll_count(er->csp_lastnodes) >= cacheex_maxhop(cl) // check max 10 nodes to push -#ifdef CS_CACHEEX_AIO - && (!er->localgenerated || (er->localgenerated && (ll_count(er->csp_lastnodes) >= cacheex_maxhop_lg(cl)))) // check maxhop_lg if cw is lg-flagged -#endif - ) - { -#ifdef CS_CACHEEX_AIO - cs_log_dbg(D_CACHEEX, "cacheex: nodelist reached %d nodes(non-lg) or reached %d nodes(lg), no push", cacheex_maxhop(cl), cacheex_maxhop_lg(cl)); -#else - cs_log_dbg(D_CACHEEX, "cacheex: nodelist reached %d nodes, no push", cacheex_maxhop(cl)); -#endif - return 0; - } - - if(cl->reader) - { - if(!cl->reader->tcp_connected) - { - cs_log_dbg(D_CACHEEX, "cacheex: not connected %s -> no push", username(cl)); - return 0; - } - } - - //if(chk_is_null_nodeid(remote_node)){ - if(!cl->ncd_skey[8]) - { - cs_log_dbg(D_CACHEEX, "cacheex: NO peer_node_id got yet, skip!"); - return 0; - } - - uint8_t *remote_node = cl->ncd_skey; //it is sended by reader(mode 2) or client (mode 3) each 30s using keepalive msgs - - //search existing peer nodes: - LL_LOCKITER *li = ll_li_create(er->csp_lastnodes, 0); - uint8_t *node; - while((node = ll_li_next(li))) - { - cs_log_dbg(D_CACHEEX, "cacheex: check node %" PRIu64 "X == %" PRIu64 "X ?", cacheex_node_id(node), cacheex_node_id(remote_node)); - if(memcmp(node, remote_node, 8) == 0) - { - break; - } - } - ll_li_destroy(li); - - // node found, so we got it from there, do not push: - if(node) - { - cs_log_dbg(D_CACHEEX, - "cacheex: node %" PRIu64 "X found in list => skip push!", cacheex_node_id(node)); - return 0; - } - - // check if cw is already pushed - if(check_is_pushed(er->cw_cache, cl)) - { return 0; } - - cs_log_dbg(D_CACHEEX, "cacheex: push ok %" PRIu64 "X to %" PRIu64 "X %s", cacheex_node_id(camd35_node_id), cacheex_node_id(remote_node), username(cl)); - - return 1; -} - -static int32_t camd35_cacheex_push_out(struct s_client *cl, struct ecm_request_t *er) -{ - int8_t rc = (er->rc < E_NOTFOUND) ? E_FOUND : er->rc; - if(rc != E_FOUND && rc != E_UNHANDLED) { return -1; } // Maybe later we could support other rcs - - // E_FOUND : we have the CW, - // E_UNHANDLED : incoming ECM request - - if(cl->reader) - { - if(!camd35_tcp_connect(cl)) - { - cs_log_dbg(D_CACHEEX, "cacheex: not connected %s -> no push", username(cl)); - return (-1); - } - } - - uint32_t size = sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw) + sizeof(uint8_t) + -#ifdef CS_CACHEEX_AIO - (ll_count(er->csp_lastnodes) + 1) * 8 + sizeof(uint8_t); -#else - (ll_count(er->csp_lastnodes) + 1) * 8; -#endif - uint8_t *buf; - if(!cs_malloc(&buf, size + 20)) // camd35_send() adds +20 - { return -1; } - - buf[0] = 0x3f; // New Command: Cache-push - buf[1] = size & 0xff; - buf[2] = size >> 8; - buf[3] = rc; - - i2b_buf(2, er->srvid, buf + 8); - i2b_buf(2, er->caid, buf + 10); - i2b_buf(4, er->prid, buf + 12); - // i2b_buf(2, er->idx, buf + 16); // Not relevant...? - - if(er->cwc_cycletime && er->cwc_next_cw_cycle < 2) - { - buf[18] = er->cwc_cycletime; // contains cwc stage3 cycletime - if(er->cwc_next_cw_cycle == 1) - { buf[18] = (buf[18] | 0x80); } // set bit 8 to high - - if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode) - { cl->account->cwc_info++; } - else if((cl->typ == 'p' || cl->typ == 'r') && (cl->reader && cl->reader->cacheex.mode)) - { cl->cwc_info++; } - - cs_log_dbg(D_CWC, "CWC (CE) push to %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(cl), er->cwc_cycletime, er->cwc_next_cw_cycle, er->caid, er->prid, er->srvid); - } - - buf[19] = er->ecm[0] != 0x80 && er->ecm[0] != 0x81 ? 0 : er->ecm[0]; - - uint8_t *ofs = buf + 20; - - // write oscam ecmd5: - memcpy(ofs, er->ecmd5, sizeof(er->ecmd5)); // 16 - ofs += sizeof(er->ecmd5); - - // write csp hashcode: - i2b_buf(4, CSP_HASH_SWAP(er->csp_hash), ofs); - ofs += 4; - - // write cw: - memcpy(ofs, er->cw, sizeof(er->cw)); // 16 - ofs += sizeof(er->cw); - - // write node count: - *ofs = ll_count(er->csp_lastnodes) + 1; - ofs++; - - // write own node: - memcpy(ofs, camd35_node_id, 8); - ofs += 8; - - // write other nodes: - LL_LOCKITER *li = ll_li_create(er->csp_lastnodes, 0); - uint8_t *node; - while((node = ll_li_next(li))) - { - memcpy(ofs, node, 8); - ofs += 8; - } - ll_li_destroy(li); - -#ifdef CS_CACHEEX_AIO - // add localgenerated cw-flag - if(er->localgenerated) - { - *ofs = 1; - } - else - { - *ofs = 0xFF; - } -#endif - int32_t res = camd35_send(cl, buf, size); - NULLFREE(buf); - return res; -} - -static void camd35_cacheex_push_in(struct s_client *cl, uint8_t *buf) -{ - int8_t rc = buf[3]; - if(rc != E_FOUND && rc != E_UNHANDLED) // Maybe later we could support other rcs - { return; } - - ECM_REQUEST *er; - uint16_t size = buf[1] | (buf[2] << 8); - if(size < sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw)) - { - cs_log_dbg(D_CACHEEX, "cacheex: %s received old cache-push format! data ignored!", username(cl)); - return; - } - - if(!(er = get_ecmtask())) - { return; } - - er->srvid = b2i(2, buf + 8); - er->caid = b2i(2, buf + 10); - er->prid = b2i(4, buf + 12); - er->pid = b2i(2, buf + 16); - er->ecm[0] = buf[19]!=0x80 && buf[19]!=0x81 ? 0 : buf[19]; // odd/even byte, usefull to send it over CSP and to check cw for swapping - er->rc = rc; - - er->ecmlen = 0; - - if(buf[18]) - { - if(buf[18] & (0x01 << 7)) - { - er->cwc_cycletime = (buf[18] & 0x7F); // remove bit 8 to get cycletime - er->cwc_next_cw_cycle = 1; - } - else - { - er->cwc_cycletime = buf[18]; - er->cwc_next_cw_cycle = 0; - } - } - - uint8_t *ofs = buf + 20; - - // Read ecmd5 - memcpy(er->ecmd5, ofs, sizeof(er->ecmd5)); // 16 - ofs += sizeof(er->ecmd5); - - if(!check_cacheex_filter(cl, er)) - { - return; - } - -#ifdef CS_CACHEEX_AIO - // check incoming cache - if(check_client(cl) && cl->typ == 'p' && cl->reader && cl->reader->cacheex.mode == 2 - && ( (cl->reader->cacheex.filter_caidtab.cevnum > 0 && !chk_csp_ctab(er, &cl->reader->cacheex.filter_caidtab)) // reader cacheex_ecm_filter not matching if set - || (cl->reader->cacheex.filter_caidtab.cevnum == 0 && (cl->reader->cacheex.feature_bitfield & 4) && cfg.cacheex_filter_caidtab_aio.cevnum > 0 && !chk_csp_ctab(er, &cfg.cacheex_filter_caidtab_aio)) // global cacheex_ecm_filter_aio not matching if set - || (cl->reader->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab_aio.cevnum == 0 && cfg.cacheex_filter_caidtab.cevnum > 0 && !chk_csp_ctab(er, &cfg.cacheex_filter_caidtab)) // global cacheex_ecm_filter not matching if set - ) - ) - { - cs_log_dbg(D_CACHEEX, "cacheex: received cache not matching cacheex_ecm_filter => pushing filter again"); - camd35_cacheex_send_push_filter(cl, 2); // get cache != cacheex_ecm_filter, send filter again - remote restarted - if(cl->reader->cacheex.feature_bitfield & 4) - camd35_cacheex_feature_trigger(cl, 4, 2); - free_push_in_ecm(er); - return; - } - - if(check_client(cl) && cl->typ == 'c' && cl->account && cl->account->cacheex.mode == 3 - && ( (cl->account->cacheex.filter_caidtab.cevnum > 0 && !chk_csp_ctab(er, &cl->account->cacheex.filter_caidtab)) // account cacheex_ecm_filter not matching if set - || (cl->account->cacheex.filter_caidtab.cevnum == 0 && (cl->account->cacheex.feature_bitfield & 4) && cfg.cacheex_filter_caidtab_aio.cevnum > 0 && !chk_csp_ctab(er, &cfg.cacheex_filter_caidtab_aio)) // global cacheex_ecm_filter_aio not matching if set - || (cl->account->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab_aio.cevnum == 0 && cfg.cacheex_filter_caidtab.cevnum > 0 && !chk_csp_ctab(er, &cfg.cacheex_filter_caidtab)) // global cacheex_ecm_filter not matching if set - ) - ) - { - cs_log_dbg(D_CACHEEX, "cacheex: received cache not matching cacheex_ecm_filter => pushing filter again"); - camd35_cacheex_send_push_filter(cl, 3); // get cache != cacheex_ecm_filter, send filter again - remote restarted - if(cl->account->cacheex.feature_bitfield & 4) - camd35_cacheex_feature_trigger(cl, 4, 3); - free_push_in_ecm(er); - return; - } -#endif - - // Read csp_hash: - er->csp_hash = CSP_HASH_SWAP(b2i(4, ofs)); - ofs += 4; - - // Read cw: - memcpy(er->cw, ofs, sizeof(er->cw)); // 16 - ofs += sizeof(er->cw); - - // Check auf neues Format: - uint8_t *data; - if(size > (sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw))) - { - - // Read lastnodes: - uint8_t count = *ofs; - ofs++; - -#ifndef CS_CACHEEX_AIO - // check max nodes: - if(count > cacheex_maxhop(cl)) - { - cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes (max=%d), ignored! %s", (int32_t)count, cacheex_maxhop(cl), username(cl)); - NULLFREE(er); - return; - } -#endif - cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes %s", (int32_t)count, username(cl)); - if (er){ - er->csp_lastnodes = ll_create("csp_lastnodes"); - } - while(count) - { - if(!cs_malloc(&data, 8)) - { break; } - memcpy(data, ofs, 8); - ofs += 8; - ll_append(er->csp_lastnodes, data); - count--; - cs_log_dbg(D_CACHEEX, "cacheex: received node %" PRIu64 "X %s", cacheex_node_id(data), username(cl)); - } - -#ifdef CS_CACHEEX_AIO - // check byte after nodelist for "localgenerated CW"-flag - if(b2i(1, ofs) == 1) - { - er->localgenerated = 1; - cs_log_dbg(D_CACHEEX, "cacheex: received ECM with localgenerated flag %04X@%06X:%04X %s", er->caid, er->prid, er->srvid, username(cl)); - - // check max nodes for lg flagged cw: - if(ll_count(er->csp_lastnodes) > cacheex_maxhop_lg(cl)) - { - cs_log_dbg(D_CACHEEX, "cacheex: received (lg) %d nodes (max=%d), ignored! %s", ll_count(er->csp_lastnodes), cacheex_maxhop_lg(cl), username(cl)); - free_push_in_ecm(er); - return; - } - } - // without localgenerated flag - else - { - // check max nodes: - if(ll_count(er->csp_lastnodes) > cacheex_maxhop(cl)) - { - cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes (max=%d), ignored! %s", ll_count(er->csp_lastnodes), cacheex_maxhop(cl), username(cl)); - free_push_in_ecm(er); - return; - } - - if( - (cl->typ == 'p' && cl->reader && cl->reader->cacheex.mode == 2 && !chk_srvid_localgenerated_only_exception(er) // cx1&2 - && ( - // !aio - (cl->cacheex_aio_checked && !cl->reader->cacheex.feature_bitfield - && ( - !cfg.cacheex_lg_only_in_aio_only && !cl->reader->cacheex.lg_only_in_aio_only - && (cfg.cacheex_localgenerated_only_in || cl->reader->cacheex.localgenerated_only_in || chk_lg_only(er, &cl->reader->cacheex.lg_only_in_tab) || chk_lg_only(er, &cfg.cacheex_lg_only_in_tab)) - ) - ) - || - // aio - (cl->cacheex_aio_checked && cl->reader->cacheex.feature_bitfield - && ( - cfg.cacheex_localgenerated_only_in || cl->reader->cacheex.localgenerated_only_in || chk_lg_only(er, &cl->reader->cacheex.lg_only_in_tab) || chk_lg_only(er, &cfg.cacheex_lg_only_in_tab) - ) - ) - ) - ) - || - (cl->typ == 'c' && cl->account && cl->account->cacheex.mode == 3 && !chk_srvid_localgenerated_only_exception(er) // cx3 - && ( - // !aio - (cl->cacheex_aio_checked && !cl->account->cacheex.feature_bitfield - && ( - !cfg.cacheex_lg_only_in_aio_only && !cl->account->cacheex.lg_only_in_aio_only - && (cfg.cacheex_localgenerated_only_in || cl->account->cacheex.localgenerated_only_in || chk_lg_only(er, &cl->account->cacheex.lg_only_in_tab) || chk_lg_only(er, &cfg.cacheex_lg_only_in_tab)) - ) - ) - || - // aio - (cl->cacheex_aio_checked && cl->account->cacheex.feature_bitfield - && ( - cfg.cacheex_localgenerated_only_in || cl->account->cacheex.localgenerated_only_in || chk_lg_only(er, &cl->account->cacheex.lg_only_in_tab) || chk_lg_only(er, &cfg.cacheex_lg_only_in_tab) - ) - ) - ) - ) - ) - { - cs_log_dbg(D_CACHEEX, "cacheex: drop ECM without localgenerated flag %04X@%06X:%04X %s", er->caid, er->prid, er->srvid, username(cl)); - free_push_in_ecm(er); - return; - } - } -#endif - } - else - { - cs_log_dbg(D_CACHEEX, "cacheex: received old cachex from %s", username(cl)); - er->csp_lastnodes = ll_create("csp_lastnodes"); - } - - // store remote node id if we got one. The remote node is the first node in the node list - data = ll_has_elements(er->csp_lastnodes); - if(data && !cl->ncd_skey[8]) // Ok, this is tricky, we use newcamd key storage for saving the remote node - { - memcpy(cl->cxnodeid_last, data, 8); - cl->cxnodeid_last[8] = 1; - cl->cxnodeid_changer_detected = 0; - memcpy(cl->ncd_skey, data, 8); - cl->ncd_skey[8] = 1; // Mark as valid node - } - cs_log_dbg(D_CACHEEX, "cacheex: received cacheex from remote node id %" PRIu64 "X", cacheex_node_id(cl->ncd_skey)); - - // for compatibility: add peer node if no node received (not working now, maybe later): - if(!ll_count(er->csp_lastnodes) && cl->ncd_skey[8]) - { - if(!cs_malloc(&data, 8)) - { -#ifdef CS_CACHEEX_AIO - free_push_in_ecm(er); -#endif - return; - } - memcpy(data, cl->ncd_skey, 8); - ll_append(er->csp_lastnodes, data); - cs_log_dbg(D_CACHEEX, "cacheex: added missing remote node id %" PRIu64 "X", cacheex_node_id(data)); - } - -#ifdef CS_CACHEEX_AIO - if (er->cwc_cycletime && er->cwc_next_cw_cycle < 2) - { - if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode) - { cl->account->cwc_info++; } - else if((cl->typ == 'p' || cl->typ == 'r') && (cl->reader && cl->reader->cacheex.mode)) - { cl->cwc_info++; } - cs_log_dbg(D_CWC, "CWC (CE) received from %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(cl), er->cwc_cycletime, er->cwc_next_cw_cycle, er->caid, er->prid, er->srvid); - } -#endif - cacheex_add_to_cache(cl, er); -} - -void camd35_cacheex_recv_ce1_cwc_info(struct s_client *cl, uint8_t *buf, int32_t idx) -{ - if(!(buf[0] == 0x01 && buf[18] < 0xFF && buf[18] > 0x00)) // cwc info ; normal camd3 ecms send 0xFF but we need no cycletime of 255 ;) - return; - - ECM_REQUEST *er = NULL; - int32_t i; - - for(i = 0; i < cfg.max_pending; i++) - { - if (cl->ecmtask[i].idx == idx) - { - er = &cl->ecmtask[i]; - break; - } - } - - if(!er) - { return; } - - int8_t rc = buf[3]; - if(rc != E_FOUND) - { return; } - - if(buf[18]) - { - if(buf[18] & (0x01 << 7)) - { - er->cwc_cycletime = (buf[18] & 0x7F); // remove bit 8 to get cycletime - er->parent->cwc_cycletime = er->cwc_cycletime; - er->cwc_next_cw_cycle = 1; - er->parent->cwc_next_cw_cycle = er->cwc_next_cw_cycle; - } - else - { - er->cwc_cycletime = buf[18]; - er->parent->cwc_cycletime = er->cwc_cycletime; - er->cwc_next_cw_cycle = 0; - er->parent->cwc_next_cw_cycle = er->cwc_next_cw_cycle; - } - } - - if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode) - { cl->account->cwc_info++; } - else if((cl->typ == 'p' || cl->typ == 'r') && (cl->reader && cl->reader->cacheex.mode)) - { cl->cwc_info++; } - - cs_log_dbg(D_CWC, "CWC (CE1) received from %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(cl), er->cwc_cycletime, er->cwc_next_cw_cycle, er->caid, er->prid, er->srvid); - -} - - -/** - * when a server client connects - */ -static void camd35_server_client_init(struct s_client *cl) -{ - if(!cl->init_done) - { - cl->cacheex_needfilter = 1; - } -} - -/** - * store received remote id - */ -static void camd35_cacheex_push_receive_remote_id(struct s_client *cl, uint8_t *buf) -{ - - memcpy(cl->ncd_skey, buf + 20, 8); - cl->ncd_skey[8] = 1; - if (!cl->cxnodeid_last[8]) - { - memcpy(cl->cxnodeid_last, buf + 20, 8); - cl->cxnodeid_last[8] = 1; - } - - if (cl->cxnodeid_last[8] && (memcmp(cl->ncd_skey, cl->cxnodeid_last, 8) != 0)) - { - cs_log_dbg(D_CACHEEX, "cacheex: received id answer from %s: %" PRIu64 "X [previous nodeid: %" PRIu64 "X ] nodeid changed!", username(cl), cacheex_node_id(cl->ncd_skey), cacheex_node_id(cl->cxnodeid_last)); - cl->cxnodeid_changer_detected = 1; - } - else - { - cl->cxnodeid_changer_detected = 0; - } -} - - -void camd35_cacheex_init_dcw(struct s_client *client, ECM_REQUEST *er) -{ - uint8_t *buf = er->src_data; // get orig request - - if(((client->typ == 'c' && client->account && client->account->cacheex.mode) - || ((client->typ == 'p' || client->typ == 'r') && (client->reader && client->reader->cacheex.mode))) - && er->cwc_cycletime && er->cwc_next_cw_cycle < 2) // ce1 - { - buf[18] = er->cwc_cycletime; // contains cwc stage3 cycletime - if(er->cwc_next_cw_cycle == 1) - { buf[18] = (buf[18] | 0x80); } // set bit 8 to high - if(client->typ == 'c' && client->account && client->account->cacheex.mode) - { client->account->cwc_info++; } - else if((client->typ == 'p' || client->typ == 'r') && (client->reader && client->reader->cacheex.mode)) - { client->cwc_info++; } - cs_log_dbg(D_CWC, "CWC (CE1) push to %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(client), er->cwc_cycletime, er->cwc_next_cw_cycle, er->caid, er->prid, er->srvid); - buf[19] = er->ecm[0]; - } -} - -/** - * send own id - */ -void camd35_cacheex_push_send_own_id(struct s_client *cl, uint8_t *mbuf) -{ - uint8_t rbuf[32]; // minimal size - if(!cl->crypted) { return; } - cs_log_dbg(D_CACHEEX, "cacheex: received id request from node %" PRIu64 "X %s", cacheex_node_id(mbuf + 20), username(cl)); - memset(rbuf, 0, sizeof(rbuf)); - rbuf[0] = 0x3e; - rbuf[1] = 12; - rbuf[2] = 0; - memcpy(rbuf + 20, camd35_node_id, 8); - cs_log_dbg(D_CACHEEX, "cacheex: sending own id %" PRIu64 "X request %s", cacheex_node_id(camd35_node_id), username(cl)); - camd35_send(cl, rbuf, 12); // send adds +20 -} - -bool camd35_cacheex_server(struct s_client *client, uint8_t *mbuf) -{ - switch(mbuf[0]) - { - case 0x3c: // Cache-push filter request - if(client->account && client->account->cacheex.mode==2){ - camd35_cacheex_push_filter(client, mbuf, 2); - } - break; - case 0x3d: // Cache-push id request - camd35_cacheex_push_receive_remote_id(client, mbuf); // reader send request id with its nodeid, so we save it! - camd35_cacheex_push_send_own_id(client, mbuf); - if(client->cacheex_needfilter && client->account && client->account->cacheex.mode==3){ - camd35_cacheex_send_push_filter(client, 3); - client->cacheex_needfilter = 0; - } -#ifdef CS_CACHEEX_AIO - if(!client->cacheex_aio_checked && ((client->account && client->account->cacheex.mode > 0) || (client->reader && client->reader->cacheex.mode > 0))) - { - camd35_cacheex_feature_request(client); - client->cacheex_aio_checked = 1; - } -#endif - break; - case 0x3e: // Cache-push id answer - camd35_cacheex_push_receive_remote_id(client, mbuf); - break; - case 0x3f: // Cache-push - camd35_cacheex_push_in(client, mbuf); - break; -#ifdef CS_CACHEEX_AIO - case 0x40: // cacheex-features request - camd35_cacheex_feature_request_reply(client, mbuf); - break; - case 0x41: // cacheex-features answer - // camd35_cacheex_feature_request_save(client, mbuf); - break; - case 0x42: // cacheex-feature trigger in - camd35_cacheex_feature_trigger_in(client, mbuf); - break; -#endif - default: - return 0; // Not processed by cacheex - } - return 1; // Processed by cacheex -} - -bool camd35_cacheex_recv_chk(struct s_client *client, uint8_t *buf) -{ - struct s_reader *rdr = client->reader; - switch(buf[0]) - { - case 0x3c: // Cache-push filter request - if(rdr->cacheex.mode==3){ - camd35_cacheex_push_filter(client, buf, 3); - } - break; - case 0x3d: // Cache-push id request - camd35_cacheex_push_receive_remote_id(client, buf); // client send request id with its nodeid, so we save it! - camd35_cacheex_push_send_own_id(client, buf); - break; - case 0x3e: // Cache-push id answer - camd35_cacheex_push_receive_remote_id(client, buf); -#ifdef CS_CACHEEX_AIO - if(!client->cacheex_aio_checked && ((client->account && client->account->cacheex.mode > 0) || (client->reader && client->reader->cacheex.mode > 0))) - { - camd35_cacheex_feature_request(client); - client->cacheex_aio_checked = 1; - } -#endif - break; - case 0x3f: // cache-push - camd35_cacheex_push_in(client, buf); - break; -#ifdef CS_CACHEEX_AIO - case 0x40: // cacheex-features request - camd35_cacheex_feature_request_reply(client, buf); - break; - case 0x41: // cacheex-features answer - // camd35_cacheex_feature_request_save(client, buf); - break; - case 0x42: // cacheex-feature trigger in - camd35_cacheex_feature_trigger_in(client, buf); - break; -#endif - default: - return 0; // Not processed by cacheex - } - return 1; // Processed by cacheex -} - -/** - * request remote id - */ -void camd35_cacheex_push_request_remote_id(struct s_client *cl) -{ - uint8_t rbuf[32]; // minimal size - memset(rbuf, 0, sizeof(rbuf)); - rbuf[0] = 0x3d; - rbuf[1] = 12; - rbuf[2] = 0; - memcpy(rbuf + 20, camd35_node_id, 8); - cs_log_dbg(D_CACHEEX, "cacheex: sending id request to %s", username(cl)); - camd35_send(cl, rbuf, 12); // send adds +20 -} - -void camd35_cacheex_module_init(struct s_module *ph) -{ - ph->c_cache_push = camd35_cacheex_push_out; - ph->c_cache_push_chk = camd35_cacheex_push_chk; - ph->s_init = camd35_server_client_init; -} - -#endif diff --git a/module-camd35-cacheex.h b/module-camd35-cacheex.h old mode 100644 new mode 100755 diff --git a/module-camd35.c b/module-camd35.c old mode 100644 new mode 100755 diff --git a/module-camd35.h b/module-camd35.h old mode 100644 new mode 100755 diff --git a/module-cccam-cacheex.c b/module-cccam-cacheex.c old mode 100644 new mode 100755 diff --git a/module-cccam-cacheex.h b/module-cccam-cacheex.h old mode 100644 new mode 100755 diff --git a/module-cccam-data.h b/module-cccam-data.h old mode 100644 new mode 100755 diff --git a/module-cccam.c b/module-cccam.c old mode 100644 new mode 100755 diff --git a/module-cccam.h b/module-cccam.h old mode 100644 new mode 100755 diff --git a/module-cccshare.c b/module-cccshare.c old mode 100644 new mode 100755 diff --git a/module-cccshare.h b/module-cccshare.h old mode 100644 new mode 100755 diff --git a/module-constcw.c b/module-constcw.c old mode 100644 new mode 100755 diff --git a/module-csp.c b/module-csp.c old mode 100644 new mode 100755 diff --git a/module-cw-cycle-check.c b/module-cw-cycle-check.c old mode 100644 new mode 100755 diff --git a/module-cw-cycle-check.h b/module-cw-cycle-check.h old mode 100644 new mode 100755 diff --git a/module-dvbapi-azbox.c b/module-dvbapi-azbox.c old mode 100644 new mode 100755 diff --git a/module-dvbapi-azbox.h b/module-dvbapi-azbox.h old mode 100644 new mode 100755 diff --git a/module-dvbapi-chancache.c b/module-dvbapi-chancache.c old mode 100644 new mode 100755 diff --git a/module-dvbapi-chancache.h b/module-dvbapi-chancache.h old mode 100644 new mode 100755 diff --git a/module-dvbapi-coolapi-legacy.c b/module-dvbapi-coolapi-legacy.c old mode 100644 new mode 100755 diff --git a/module-dvbapi-coolapi.c b/module-dvbapi-coolapi.c old mode 100644 new mode 100755 diff --git a/module-dvbapi-coolapi.h b/module-dvbapi-coolapi.h old mode 100644 new mode 100755 diff --git a/module-dvbapi-mca.c b/module-dvbapi-mca.c old mode 100644 new mode 100755 diff --git a/module-dvbapi-mca.h b/module-dvbapi-mca.h old mode 100644 new mode 100755 diff --git a/module-dvbapi-stapi.c b/module-dvbapi-stapi.c old mode 100644 new mode 100755 diff --git a/module-dvbapi-stapi.h b/module-dvbapi-stapi.h old mode 100644 new mode 100755 diff --git a/module-dvbapi-stapi5.c b/module-dvbapi-stapi5.c old mode 100644 new mode 100755 diff --git a/module-dvbapi.c b/module-dvbapi.c old mode 100644 new mode 100755 diff --git a/module-dvbapi.h b/module-dvbapi.h old mode 100644 new mode 100755 diff --git a/module-emulator-biss.c b/module-emulator-biss.c deleted file mode 100755 index a6b0c9e..0000000 --- a/module-emulator-biss.c +++ /dev/null @@ -1,883 +0,0 @@ -#define MODULE_LOG_PREFIX "emu" - -#include "globals.h" - -#ifdef WITH_EMU - -#include "module-emulator-osemu.h" -#include "module-emulator-biss.h" -#include "oscam-aes.h" -#include "oscam-string.h" -#include -#include -//#include -#include - -// DVB-CISSA v1 IV as defined in ETSI TS 103 127 -static const uint8_t dvb_cissa_iv[16] = -{ - 0x44, 0x56, 0x42, 0x54, 0x4D, 0x43, 0x50, 0x54, - 0x41, 0x45, 0x53, 0x43, 0x49, 0x53, 0x53, 0x41 -}; - -static void unify_orbitals(uint32_t *namespace) -{ - // Unify orbitals to produce same namespace among users - // Set positions according to http://satellites-xml.org - - uint16_t pos = (*namespace & 0x0FFF0000) >> 16; - - switch (pos) - { - case 29: // Rascom QAF 1R - case 31: // Eutelsat 3B - { - pos = 30; - break; - } - - case 49: - case 50: // SES 5 - { - pos = 48; // Astra 4A - break; - } - - case 215: - { - pos = 216; // Eutelsat 21B - break; - } - - case 285: // Astra 2E - { - pos = 282; // Astra 2F/2G - break; - } - - case 328: // Intelsat 28 - case 329: - case 331: // Eutelsat 33C - { - pos = 330; - break; - } - - case 359: // Eutelsat 36B - case 361: // Express AMU1 - { - pos = 360; - break; - } - - case 451: // Intelsat 904 - { - pos = 450; // Intelsat 12 - break; - } - - case 550: - case 551: // G-Sat 8/16 - { - pos = 549; // Yamal 402 - break; - } - - case 748: - case 749: // ABS 2A - { - pos = 750; - break; - } - - case 848: // Horizons 2 - case 852: // Intelsat 15 - { - pos = 850; - break; - } - - case 914: // Mesasat 3a - { - pos = 915; // Mesasat 3/3b - break; - } - - case 934: // G-Sat 17 - case 936: // Insat 4B - { - pos = 935; // G-Sat 15 - break; - } - - case 3600 - 911: // Nimiq 6 - { - pos = 3600 - 910; // Galaxy 17 - break; - } - - case 3600 - 870: // SES 2 - case 3600 - 872: // TKSat 1 - { - pos = 3600 - 871; - break; - } - - case 3600 - 432: // Sky Brasil 1 - case 3600 - 430: // Intelsat 11 - { - pos = 3600 - 431; - break; - } - - case 3600 - 376: // Telstar 11N - case 3600 - 374: // NSS 10 - { - pos = 3600 - 375; - break; - } - - case 3600 - 359: // Hispasat 36W-1 - { - pos = 3600 - 360; // Eutelsat 36 West A - break; - } - - case 3600 - 81: // Eutelsat 8 West B - { - pos = 3600 - 80; - break; - } - - case 3600 - 73: // Eutelsat 7 West A - case 3600 - 72: - case 3600 - 71: - { - pos = 3600 - 70; // Nilesat 201 - break; - } - - case 3600 - 10: // Intelsat 10-02 - case 3600 - 9: // Thor 6 - case 3600 - 7: // Thor 7 - case 3600 - 6: // Thor 7 - { - pos = 3600 - 8; // Thor 5 - break; - } - } - - *namespace = (*namespace & 0xF000FFFF) | (pos << 16); -} - -static void annotate(char *buf, uint8_t len, const uint8_t *ecm, uint16_t ecmLen, - uint32_t hash, int8_t isNamespaceHash, int8_t datecoded) -{ - // Extract useful information to append to the "Example key ..." message. - // - // For feeds, the orbital position & frequency are usually embedded in the namespace. - // See https://github.com/OpenPLi/enigma2/blob/develop/lib/dvb/frontend.cpp#L476 - // hash = (sat.orbital_position << 16); - // hash |= ((sat.frequency/1000)&0xFFFF)|((sat.polarisation&1) << 15); - // - // If the onid & tsid appear to be a unique DVB identifier, enigma2 strips the frequency - // from our namespace. See https://github.com/OpenPLi/enigma2/blob/develop/lib/dvb/scan.cpp#L55 - // In that case, our annotation contains the onid:tsid:sid triplet in lieu of frequency. - // - // For the universal case, we print the number of elementary stream pids & pmtpid. - // The sid and current time are included for all. Examples: - // - // F 1A2B3C4D 00000000 XXXXXXXXXXXXXXXX ; 110.5W 12345H sid:0001 added: 2017-10-17 @ 13:14:15 // namespace - // F 1A2B3C4D 20180123 XXXXXXXXXXXXXXXX ; 33.5E ABCD:9876:1234 added: 2017-10-17 @ 13:14:15 // stripped namespace - // F 1A2B3C4D 20180123 XXXXXXXXXXXXXXXX ; av:5 pmt:0134 sid:0001 added: 2017-10-17 @ 13:14:15 // universal - - uint8_t pidcount; - uint16_t frequency, degrees, pmtpid, srvid, tsid, onid; - uint32_t ens; - char compass, polarisation, timeStr1[9], timeStr2[19]; - - if (datecoded) - { - date_to_str(timeStr1, sizeof(timeStr1), 4, 3); - } - else - { - snprintf(timeStr1, sizeof(timeStr1), "00000000"); - } - - date_to_str(timeStr2, sizeof(timeStr2), 0, 2); - - if (isNamespaceHash) // Namespace hash - { - ens = b2i(4, ecm + ecmLen - 4); // Namespace will be the last 4 bytes of the ecm - degrees = (ens >> 16) & 0x0FFF; // Remove not-a-pid flag - - if (degrees > 1800) - { - degrees = 3600 - degrees; - compass = 'W'; - } - else - { - compass = 'E'; - } - - if (0 == (ens & 0xFFFF)) // Stripped namespace hash - { - srvid = b2i(2, ecm + 3); - tsid = b2i(2, ecm + ecmLen - 8); - onid = b2i(2, ecm + ecmLen - 6); - // Printing degree sign "\u00B0" requires c99 standard - snprintf(buf, len, "F %08X %s XXXXXXXXXXXXXXXX ; %5.1f%c %04X:%04X:%04X added: %s", - hash, timeStr1, degrees / 10.0, compass, onid, tsid, srvid, timeStr2); - } - else // Full namespace hash - { - srvid = b2i(2, ecm + 3); - frequency = ens & 0x7FFF; // Remove polarity bit - polarisation = ens & 0x8000 ? 'V' : 'H'; - // Printing degree sign "\u00B0" requires c99 standard - snprintf(buf, len, "F %08X %s XXXXXXXXXXXXXXXX ; %5.1f%c %5d%c sid:%04X added: %s", - hash, timeStr1, degrees / 10.0, compass, frequency, polarisation, srvid, timeStr2); - } - } - else // Universal hash - { - srvid = b2i(2, ecm + 3); - pmtpid = b2i(2, ecm + 5); - pidcount = (ecmLen - 15) / 2; // video + audio pids count - snprintf(buf, len, "F %08X %s XXXXXXXXXXXXXXXX ; av:%d pmt:%04X sid:%04X added: %s", - hash, timeStr1, pidcount, pmtpid, srvid, timeStr2); - } -} - -static int8_t is_common_hash(uint32_t hash) -{ - // Check universal hash against a number of commnon universal - // hashes in order to warn users about potential key clashes - - switch (hash) - { - case 0xBAFCD9FD: // 0001 0020 0200 1010 1020 (most common hash) - return 1; - case 0xA6A4FBD4: // 0001 0800 0200 1010 1020 - return 1; - case 0xEFAB7A4D: // 0001 0800 1010 1020 0200 - return 1; - case 0x83FA15D1: // 0001 0020 0134 0100 0101 - return 1; - case 0x58934C38: // 0001 0800 1010 1020 1030 0200 - return 1; - case 0x2C3CEC17: // 0001 0020 0134 0100 - return 1; - case 0x73DF7F7E: // 0001 0020 0200 1010 1020 1030 - return 1; - case 0xAFA85BC8: // 0001 0020 0021 0022 0023 - return 1; - case 0x8C51F31D: // 0001 0800 0200 1010 1020 1030 1040 - return 1; - case 0xE2F9BD29: // 0001 0800 0200 1010 1020 1030 - return 1; - case 0xB9EBE0FF: // 0001 0100 0200 1010 1020 (less common hash) - return 1; - default: - return 0; - } -} - -static int8_t is_valid_namespace(uint32_t namespace) -{ - // Note to developers: - // If we ever have a satellite at 0.0E, edit to allow stripped namespace - // '0xA0000000' with an additional test on tsid and onid being != 0 - - uint16_t orbital, frequency; - - orbital = (namespace >> 16) & 0x0FFF; - frequency = namespace & 0x7FFF; - - if ((namespace & 0xF0000000) != 0xA0000000) return 0; // Value isn't flagged as namespace - if ((namespace & 0x0FFFFFFF) == 0x00000000) return 0; // Empty namespace - if (orbital > 3599) return 0; // Allow only DVB-S - if (frequency == 0) return 1; // Stripped namespace - if (frequency >= 3400 && frequency <= 4200) return 1; // Super extended C band - if (frequency >= 10700 && frequency <= 12750) return 1; // Ku band Europe - - return 0; -} - -static int8_t get_sw(uint32_t provider, uint8_t *sw, uint8_t sw_length, int8_t dateCoded, int8_t printMsg) -{ - // If date-coded keys are enabled in the webif, this function evaluates the expiration date - // of the found keys. Expired keys are not sent to the calling function. If date-coded keys - // are disabled, then every key is sent without any evaluation. It takes the "provider" as - // input and outputs the "sw". Returns 0 (key not found, or expired) or 1 (key found). - - // printMsg: 0 => No message - // printMsg: 1 => Print message only if key is found - // printMsg: 2 => Always print message, regardless if key is found or not - - char keyExpDate[9] = "00000000"; - - if (emu_find_key('F', provider, 0, keyExpDate, sw, sw_length, 0, 0, 0, NULL)) // Key found - { - if (dateCoded) // Date-coded keys are enabled, evaluate expiration date - { - char currentDate[9]; - date_to_str(currentDate, sizeof(currentDate), 0, 3); - - if (strncmp("00000000", keyExpDate, 9) == 0 || strncmp(currentDate, keyExpDate, 9) < 0) // Evergreen or not expired - { - if (printMsg == 1 || printMsg == 2) cs_log("Key found: F %08X %s", provider, keyExpDate); - return 1; - } - else // Key expired - { - sw = NULL; // Make sure we don't send any expired key - if (printMsg == 2) cs_log("Key expired: F %08X %s", provider, keyExpDate); - return 0; - } - } - else // Date-coded keys are disabled, don't evaluate expiration date - { - if (printMsg == 1 || printMsg == 2) cs_log("Key found: F %08X %s", provider, keyExpDate); - return 1; - } - } - else // Key not found - { - if (printMsg == 2) cs_log("Key not found: F %08X", provider); - return 0; - } -} - -static int8_t biss_mode1_ecm(struct s_reader *rdr, const uint8_t *ecm, uint16_t caid, uint16_t ecm_pid, uint8_t *dw, EXTENDED_CW *cw_ex) -{ - // Oscam's fake ecm consists of [sid] [pmtpid] [pid1] [pid2] ... [pidx] [tsid] [onid] [ens] - // On enigma boxes tsid, onid and namespace should be non zero, while on non-enigma - // boxes they are usually all zero. The top 4 bits of the namespace are flagged with 0xA. - - // The emulator creates a unique channel hash using srvid and enigma namespace or - // srvid, tsid, onid and namespace (in case of namespace without frequency) and - // another weaker (not unique) hash based on every pid of the channel. This universal - // hash should be available on all types of stbs (enigma and non-enigma). - - // Key searches are made from highest priority (tightest test first) to lowest priority - // (loosest test last): - // 1. Namespace hash (only on enigma boxes) - // 2. Universal hash (all box types with emu r752+) - // 3. Valid tsid, onid combination - // 4. Reverse order pid (audio, video, pmt) - // 5. Legacy srvid, ecm pid combination - // 6. Default "All Feeds" key - - // If enabled in the webif, a date based key search is performed. If the expiration - // date has passed, the key is not sent back from get_sw(). This option is used only - // in the namespace hash, universal hash and the "All Feeds" search methods. - - uint32_t i, ens = 0, hash = 0; - uint16_t srvid, tsid = 0, onid = 0, pid, ecm_len = SCT_LEN(ecm); - uint8_t *sw, sw_length, ecm_copy[ecm_len]; - char tmp_buffer1[33], tmp_buffer2[90] = "0", tmp_buffer3[90] = "0"; - - if (caid == 0x2602 && cw_ex != NULL) // BISS2 - { - cw_ex->mode = CW_MODE_ONE_CW; - cw_ex->algo = CW_ALGO_AES128; - cw_ex->algo_mode = CW_ALGO_MODE_CBC; - memcpy(cw_ex->data, dvb_cissa_iv, 16); - - sw = cw_ex->session_word; - sw_length = 16; - } - else // BISS1 - { - sw = dw; - sw_length = 8; - } - - srvid = b2i(2, ecm + 3); - - if (ecm_len >= 17) // Likely an r752+ extended ecm - { - tsid = b2i(2, ecm + ecm_len - 8); - onid = b2i(2, ecm + ecm_len - 6); - ens = b2i(4, ecm + ecm_len - 4); - } - - // 1. Namespace hash (enigma only) - if (is_valid_namespace(ens)) - { - unify_orbitals(&ens); - memcpy(ecm_copy, ecm, ecm_len); - i2b_buf(4, ens, ecm_copy + ecm_len - 4); - - for (i = 0; i < 5; i++) // Find key matching hash made with frequency modified to: f+0, then f-1, f+1, f-2, lastly f+2 - { - ecm_copy[ecm_len - 1] = (i & 1) ? ecm_copy[ecm_len - 1] - i : ecm_copy[ecm_len - 1] + i; // frequency +/- 1, 2 MHz - - if (0 != (ens & 0xFFFF)) // Full namespace - Calculate hash with srvid and namespace only - { - i2b_buf(2, srvid, ecm_copy + ecm_len - 6); // Put [srvid] right before [ens] - hash = crc32(caid, ecm_copy + ecm_len - 6, 6); - } - else // Namespace without frequency - Calculate hash with srvid, tsid, onid and namespace - { - i2b_buf(2, srvid, ecm_copy + ecm_len - 10); // Put [srvid] right before [tsid] [onid] [ens] sequence - hash = crc32(caid, ecm_copy + ecm_len - 10, 10); - } - - if (get_sw(hash, sw, sw_length, rdr->emu_datecodedenabled, i == 0 ? 2 : 1)) // Do not print "key not found" for frequency off by 1, 2 - { - memcpy(sw + sw_length, sw, sw_length); - return EMU_OK; - } - - if (i == 0) // No key found matching our hash: create example SoftCam.Key BISS line for the live log - { - annotate(tmp_buffer2, sizeof(tmp_buffer2), ecm_copy, ecm_len, hash, 1, rdr->emu_datecodedenabled); - } - - if (0 == (ens & 0xFFFF)) // Namespace without frequency - Do not iterate - { - break; - } - } - } - - // 2. Universal hash (in r752+ style ecms that contain pmt pid) - if ((ens & 0xF0000000) == 0xA0000000) - { - hash = crc32(caid, ecm + 3, ecm_len - 3 - 8); // Do not include [tsid] [onid] [ens] in the hash - - if (get_sw(hash, sw, sw_length, rdr->emu_datecodedenabled, 2)) - { - memcpy(sw + sw_length, sw, sw_length); - return EMU_OK; - } - - // No key found matching our hash: create example SoftCam.Key BISS line for the live log - annotate(tmp_buffer3, sizeof(tmp_buffer3), ecm_copy, ecm_len, hash, 0, rdr->emu_datecodedenabled); - } - - // 3. Valid [tsid] [onid] combination (per enigma2) - if (onid != 0 && (onid != 1 || tsid >= 2) && onid < 0xFF00) - { - if (get_sw(tsid << 16 | onid, sw, sw_length, 0, 2)) - { - memcpy(sw + sw_length, sw, sw_length); - return EMU_OK; - } - } - - // 4. Reverse order pid search - // (better identifies channels with variable counts of audio pids) - // Strip [tsid] [onid] [ens] on r752+ ecms to be compatible with older versions) - if ((ens & 0xF0000000) == 0xA0000000) - { - ecm_len -= 8; - } - - for (i = ecm_len - 2; i >= 5; i -= 2) - { - pid = b2i(2, ecm + i); - - if (get_sw((srvid << 16) | pid, sw, sw_length, 0, 2)) - { - memcpy(sw + sw_length, sw, sw_length); - return EMU_OK; - } - } - - // 5. Legacy [srvid] [ecm pid] combination - if (get_sw((srvid << 16) | ecm_pid, sw, sw_length, 0, 2)) - { - memcpy(sw + sw_length, sw, sw_length); - return EMU_OK; - } - - // 6. Default BISS key for events with many feeds sharing the same session word - // (limited to local ecms, network ecms with ecm pid equal to zero are blocked) - if (ecm_pid != 0 && get_sw(0xA11FEED5, sw, sw_length, rdr->emu_datecodedenabled, 2)) - { - memcpy(sw + sw_length, sw, sw_length); - cs_hexdump(0, sw, sw_length, tmp_buffer1, sizeof(tmp_buffer1)); - cs_log("No specific match found. Using 'All Feeds' key: %s", tmp_buffer1); - return EMU_OK; - } - - // Print example key lines for available hash search methods, if no key is found - if (strncmp(tmp_buffer2, "0", 2)) cs_log("Example key based on namespace hash: %s", tmp_buffer2); - if (strncmp(tmp_buffer3, "0", 2)) cs_log("Example key based on universal hash: %s", tmp_buffer3); - - // Check if universal hash is common and warn user - if (is_common_hash(hash)) cs_log("Feed has commonly used pids, universal hash clashes in SoftCam.Key are likely!"); - - return EMU_KEY_NOT_FOUND; -} - -static inline int8_t get_ecm_key(uint16_t onid, uint16_t esid, uint8_t parity, uint8_t *key) -{ - return emu_find_key('G', onid << 16 | esid, 0, parity == 0 ? "00" : "01", key, 16, 1, 0, 0, NULL); -} - -static int8_t biss2_mode_ca_ecm(const uint8_t *ecm, EXTENDED_CW *cw_ex) -{ - uint8_t ecm_cipher_type, session_key_parity; - uint8_t session_key[16], iv[16]; - uint16_t entitlement_session_id, original_network_id, descriptor_length; - uint16_t position, ecm_length = SCT_LEN(ecm); - uint32_t payload_checksum, calculated_checksum; - char tmp_buffer[64]; - struct aes_keys aes; - - // Calculate crc32 checksum and compare against the checksum bytes of the ECM - payload_checksum = b2i(4, ecm + ecm_length - 4); - calculated_checksum = ccitt32_crc((uint8_t *)ecm, ecm_length - 4); - - if (payload_checksum != calculated_checksum) - { - cs_log_dbg(D_TRACE, "ECM checksum mismatch (payload: %08X vs calculated: %08X", - payload_checksum, calculated_checksum); - return EMU_CHECKSUM_ERROR; - } - - // Unique identifiers of the session key - entitlement_session_id = b2i(2, ecm + 3); - original_network_id = b2i(2, ecm + 8); - - ecm_cipher_type = ecm[10] >> 5; - if (ecm_cipher_type != 0) // Session words shall be encrypted with AES_128_CBC - { - cs_log("ECM cipher type %d not supported", ecm_cipher_type); - return EMU_NOT_SUPPORTED; - } - - descriptor_length = b2i(2, ecm + 10) & 0x0FFF; - position = 12 + descriptor_length; - - session_key_parity = ecm[position] >> 7; // Parity can be "00" or "01" - position++; - - if (!get_ecm_key(original_network_id, entitlement_session_id, session_key_parity, session_key)) - { - return EMU_KEY_NOT_FOUND; - } - - memcpy(iv, ecm + position, 16); // "AES_128_CBC_enc_session_word_iv" - memcpy(cw_ex->session_word, ecm + position + 16, 16); // "AES_128_CBC_enc_session_word_0" - memcpy(cw_ex->session_word + 16, ecm + position + 32, 16); // "AES_128_CBC_enc_session_word_1" - - // Delete these cs_log calls when everything is confirmed to work correctly - cs_hexdump(3, iv, 16, tmp_buffer, sizeof(tmp_buffer)); - cs_log_dbg(D_TRACE, "session_word_iv: %s", tmp_buffer); - - cs_hexdump(3, cw_ex->session_word, 16, tmp_buffer, sizeof(tmp_buffer)); - cs_log_dbg(D_TRACE, "encrypted session_word_0: %s", tmp_buffer); - - cs_hexdump(3, cw_ex->session_word + 16, 16, tmp_buffer, sizeof(tmp_buffer)); - cs_log_dbg(D_TRACE, "encrypted session_word_1: %s", tmp_buffer); - - // Decrypt session words - aes_set_key(&aes, (char *)session_key); - aes_cbc_decrypt(&aes, cw_ex->session_word, 16, iv); - memcpy(iv, ecm + position, 16); // Set iv again to the correct one - aes_cbc_decrypt(&aes, cw_ex->session_word + 16, 16, iv); - - // Delete these cs_log calls when everything is confirmed to work correctly - cs_hexdump(3, cw_ex->session_word, 16, tmp_buffer, sizeof(tmp_buffer)); - cs_log_dbg(D_TRACE, "decrypted session_word_0: %s", tmp_buffer); - - cs_hexdump(3, cw_ex->session_word + 16, 16, tmp_buffer, sizeof(tmp_buffer)); - cs_log_dbg(D_TRACE, "decrypted session_word_1: %s", tmp_buffer); - - cw_ex->mode = CW_MODE_ONE_CW; - cw_ex->algo = CW_ALGO_AES128; - cw_ex->algo_mode = CW_ALGO_MODE_CBC; - memcpy(cw_ex->data, dvb_cissa_iv, 16); - - return EMU_OK; -} - -int8_t biss_ecm(struct s_reader *rdr, const uint8_t *ecm, uint16_t caid, uint16_t ecm_pid, uint8_t *dw, EXTENDED_CW *cw_ex) -{ - switch (caid) - { - case 0x2600: - return biss_mode1_ecm(rdr, ecm, caid, ecm_pid, dw, NULL); - - case 0x2602: - return biss_mode1_ecm(rdr, ecm, caid, ecm_pid, NULL, cw_ex); - - case 0x2610: - return biss2_mode_ca_ecm(ecm, cw_ex); - - default: - cs_log("Unknown Biss caid %04X - Please report!", caid); - return EMU_NOT_SUPPORTED; - } -} - -static uint16_t parse_session_data_descriptor(const uint8_t *data, uint16_t esid, uint16_t onid, uint32_t *keysAdded) -{ - uint8_t descriptor_tag = data[0]; - uint8_t descriptor_length = data[1]; - - switch (descriptor_tag) - { - case 0x81: // session_key_descriptor - { - uint8_t session_key_type = data[2] >> 1; - if (session_key_type == 0) // AES-128 - { - uint8_t session_key_parity = data[2] & 0x01; - uint8_t session_key_data[16]; - memcpy(session_key_data, data + 3, 16); // This is the ECM key - - SAFE_MUTEX_LOCK(&emu_key_data_mutex); - if (emu_update_key('G', onid << 16 | esid, session_key_parity ? "01" : "00", session_key_data, 16, 1, NULL)) - { - (*keysAdded)++; - char tmp[33]; - cs_hexdump(0, session_key_data, 16, tmp, sizeof(tmp)); - cs_log("Key found in EMM: G %08X %02d %s", onid << 16 | esid, session_key_parity, tmp); - } - SAFE_MUTEX_UNLOCK(&emu_key_data_mutex); - } - break; - } - - case 0x82: // entitlement_flags_descriptor - break; - - default: - break; - } - - return 2 + descriptor_length; -} - -static int8_t parse_session_data(const uint8_t *data, RSA *key, uint16_t esid, uint16_t onid, uint32_t *keysAdded) -{ - // session_data is encrypted with RSA 2048 bit OAEP - // Maximum size of decrypted session_data is less than (256-41) bytes - uint8_t session_data[214]; - - if (RSA_private_decrypt(256, data, session_data, key, RSA_PKCS1_OAEP_PADDING) > 0) - { - uint16_t pos = 0; - uint16_t descriptor_length = b2i(2, session_data) & 0x0FFF; - - while (pos < descriptor_length) - { - pos += parse_session_data_descriptor(session_data + 2 + pos, esid, onid, keysAdded); - } - - return EMU_OK; - } - - return EMU_NOT_SUPPORTED; // Decryption failed for whatever reason -} - -static int8_t get_rsa_key(struct s_reader *rdr, const uint8_t *ekid, RSA **key) -{ - LL_ITER itr; - biss2_rsa_key_t *data; - - itr = ll_iter_create(rdr->ll_biss2_rsa_keys); - while ((data = ll_iter_next(&itr))) - { - if (data->ekid == ekid) - { - *key = data->key; - return 1; - } - } - - return 0; -} - -int8_t biss_emm(struct s_reader *rdr, const uint8_t *emm, uint32_t *keysAdded) -{ - uint8_t emm_cipher_type, entitlement_priv_data_loop, entitlement_key_id[8]; - uint16_t entitlement_session_id, original_network_id, descriptor_length; - uint16_t pos, emm_length = SCT_LEN(emm); - uint32_t payload_checksum, calculated_checksum; - int8_t result = EMU_NOT_SUPPORTED; - char tmp[17]; - RSA *key; - - // Calculate crc32 checksum and compare against the checksum bytes of the EMM - payload_checksum = b2i(4, emm + emm_length - 4); - calculated_checksum = ccitt32_crc((uint8_t *)emm, emm_length - 4); - - if (payload_checksum != calculated_checksum) - { - cs_log_dbg(D_TRACE, "EMM checksum mismatch (payload: %08X vs calculated: %08X", - payload_checksum, calculated_checksum); - return EMU_CHECKSUM_ERROR; - } - - // Identifiers of the session key carried in the EMM - // We just pass them to the "parse_session_data()" function - entitlement_session_id = b2i(2, emm + 3); - original_network_id = b2i(2, emm + 8); - cs_log_dbg(D_TRACE, "onid: %04X, esid: %04X", original_network_id, entitlement_session_id); - - emm_cipher_type = emm[11] >> 5; // top 3 bits; - entitlement_priv_data_loop = (emm[11] >> 4) & 0x01; // 4th bit - - if (emm_cipher_type != 0) // EMM payload is not encrypted with RSA_2048_OAEP - { - cs_log_dbg(D_TRACE, "EMM cipher type %d not supported", emm_cipher_type); - return EMU_NOT_SUPPORTED; - } - - descriptor_length = b2i(2, emm + 12) & 0x0FFF; - pos = 14 + descriptor_length; - - while (pos < emm_length - 4) - { - // Unique identifier of the public rsa key used for "session_data" encryption - memcpy(entitlement_key_id, emm + pos, 8); - pos += 8; - - if (get_rsa_key(rdr, entitlement_key_id, &key)) // Key found - { - cs_hexdump(0, entitlement_key_id, 8, tmp, sizeof(tmp)); - cs_log_dbg(D_TRACE, "RSA key found (ekid: %s)", tmp); - - // Parse "encrypted_session_data" - result = parse_session_data(emm + pos, key, entitlement_session_id, original_network_id, keysAdded); - if (result == EMU_OK) - { - break; // No need to decrypt again with another key - } - } - else // Multiple ekid's can be present in the EMM - Do not exit just yet - { - cs_hexdump(0, entitlement_key_id, 8, tmp, sizeof(tmp)); - cs_log_dbg(D_TRACE, "RSA key not found (ekid: %s)", tmp); - - result = EMU_KEY_NOT_FOUND; - } - - pos += 256; // 2048 bits - - if (entitlement_priv_data_loop) // Skip any remaining bytes - { - pos += 2 + (b2i(2, emm + pos) & 0x0FFF); - } - } - - return result; -} - -static int8_t rsa_key_exists(struct s_reader *rdr, const biss2_rsa_key_t *item) -{ - LL_ITER itr; - biss2_rsa_key_t *data; - - itr = ll_iter_create(rdr->ll_biss2_rsa_keys); - while ((data = ll_iter_next(&itr))) - { - if (data->ekid == item->ekid) - { - return 1; - } - } - - return 0; -} - -uint16_t biss_read_pem(struct s_reader *rdr, uint8_t max_keys) -{ - FILE *fp_pri = NULL; - //FILE *fp_pub = NULL; - - char tmp[256]; - uint8_t hash[32], *der = NULL; - uint16_t i, length, count = 0;; - biss2_rsa_key_t *new_item; - - if (!rdr->ll_biss2_rsa_keys) - { - rdr->ll_biss2_rsa_keys = ll_create("ll_biss2_rsa_keys"); - } - - for (i = 0; i < max_keys; i++) - { - if (!cs_malloc(&new_item, sizeof(biss2_rsa_key_t))) - { - break; // No memory available (?) - Exit - } - - snprintf(tmp, sizeof(tmp), "%sbiss2_private_%02d.pem", emu_keyfile_path, i); - if ((fp_pri = fopen(tmp, "r")) == NULL) - { - continue; // File does not exist - } - - cs_log("Reading RSA key from: biss2_private_%02d.pem", i); - - // Read RSA private key - if ((new_item->key = PEM_read_RSAPrivateKey(fp_pri, NULL, NULL, NULL)) == NULL) - { - cs_log("Error reading RSA private key"); - continue; - } - - fclose(fp_pri); - - // Write public key in PEM formatted file - /*snprintf(tmp, sizeof(tmp), "%sbiss2_public_%02d.pem", emu_keyfile_path, i); - if ((fp_pub = fopen(tmp, "w")) != NULL) - { - PEM_write_RSA_PUBKEY(fp_pub, item->key); - fclose(fp_pub); - }*/ - - // Write public key in DER formatted file - /*snprintf(tmp, sizeof(tmp), "%sbiss2_public_%02d.der", emu_keyfile_path, i); - if ((fp_pub = fopen(tmp, "wb")) != NULL) - { - i2d_RSA_PUBKEY_fp(fp_pub, item->key); - fclose(fp_pub); - }*/ - - // Encode RSA public key into DER format - if ((length = i2d_RSA_PUBKEY(new_item->key, &der)) <= 0) - { - cs_log("Error encoding to DER format"); - NULLFREE(der); - continue; - } - - // Create SHA256 digest - EVP_MD_CTX *mdctx; - if ((mdctx = EVP_MD_CTX_create()) == NULL) - { - NULLFREE(der); - continue; - } - - EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL); - EVP_DigestUpdate(mdctx, der, length); - EVP_DigestFinal_ex(mdctx, hash, NULL); - EVP_MD_CTX_destroy(mdctx); - - NULLFREE(der); - memcpy(new_item->ekid, hash, 8); - - // Add new RSA key, if not already present - if (!rsa_key_exists(rdr, new_item)) - { - ll_append(rdr->ll_biss2_rsa_keys, new_item); - count++; - } - } - - return count; -} - -#endif // WITH_EMU diff --git a/module-emulator-biss.h b/module-emulator-biss.h deleted file mode 100755 index 0f5900c..0000000 --- a/module-emulator-biss.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef MODULE_EMULATOR_BISS_H -#define MODULE_EMULATOR_BISS_H - -#ifdef WITH_EMU - -#include - -#define BISS2_MAX_RSA_KEYS 16 - -typedef struct biss2_rsa_key -{ - uint8_t ekid[8]; - RSA *key; -} biss2_rsa_key_t; - -int8_t biss_ecm(struct s_reader *rdr, const uint8_t *ecm, uint16_t caid, uint16_t ecm_pid, uint8_t *dw, EXTENDED_CW *cw_ex); -int8_t biss_emm(struct s_reader *rdr, const uint8_t *emm, uint32_t *keysAdded); -uint16_t biss_read_pem(struct s_reader *rdr, uint8_t max_keys); - -#endif // WITH_EMU - -#endif // MODULE_EMULATOR_BISS_H diff --git a/module-emulator-cryptoworks.c b/module-emulator-cryptoworks.c deleted file mode 100755 index df6509a..0000000 --- a/module-emulator-cryptoworks.c +++ /dev/null @@ -1,688 +0,0 @@ -#define MODULE_LOG_PREFIX "emu" - -#include "globals.h" - -#ifdef WITH_EMU - -#include "cscrypt/des.h" -#include "module-emulator-osemu.h" - -// Cryptoworks EMU - -static int8_t get_key(uint8_t *buf,uint32_t ident, uint8_t keyIndex, uint32_t keyLength, uint8_t isCriticalKey) -{ - char keyName[EMU_MAX_CHAR_KEYNAME]; - uint32_t tmp; - - if ((ident >> 4) == 0xD02A) - { - keyIndex &= 0xFE; // map to even number key indexes - } - - if ((ident >> 4) == 0xD00C) - { - ident = 0x0D00C0; // map provider C? to C0 - } - else if (keyIndex == 6 && ((ident >> 8) == 0x0D05)) - { - ident = 0x0D0504; // always use provider 04 system key - } - - tmp = keyIndex; - snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%.2X", tmp); - - if (emu_find_key('W', ident, 0, keyName, buf, keyLength, isCriticalKey, 0, 0, NULL)) - { - return 1; - } - - return 0; -} - -static const uint8_t cw_sbox1[64] = -{ - 0xD8, 0xD7, 0x83, 0x3D, 0x1C, 0x8A, 0xF0, 0xCF, 0x72, 0x4C, 0x4D, 0xF2, 0xED, 0x33, 0x16, 0xE0, - 0x8F, 0x28, 0x7C, 0x82, 0x62, 0x37, 0xAF, 0x59, 0xB7, 0xE0, 0x00, 0x3F, 0x09, 0x4D, 0xF3, 0x94, - 0x16, 0xA5, 0x58, 0x83, 0xF2, 0x4F, 0x67, 0x30, 0x49, 0x72, 0xBF, 0xCD, 0xBE, 0x98, 0x81, 0x7F, - 0xA5, 0xDA, 0xA7, 0x7F, 0x89, 0xC8, 0x78, 0xA7, 0x8C, 0x05, 0x72, 0x84, 0x52, 0x72, 0x4D, 0x38 -}; - -static const uint8_t cw_sbox2[64] = -{ - 0xD8, 0x35, 0x06, 0xAB, 0xEC, 0x40, 0x79, 0x34, 0x17, 0xFE, 0xEA, 0x47, 0xA3, 0x8F, 0xD5, 0x48, - 0x0A, 0xBC, 0xD5, 0x40, 0x23, 0xD7, 0x9F, 0xBB, 0x7C, 0x81, 0xA1, 0x7A, 0x14, 0x69, 0x6A, 0x96, - 0x47, 0xDA, 0x7B, 0xE8, 0xA1, 0xBF, 0x98, 0x46, 0xB8, 0x41, 0x45, 0x9E, 0x5E, 0x20, 0xB2, 0x35, - 0xE4, 0x2F, 0x9A, 0xB5, 0xDE, 0x01, 0x65, 0xF8, 0x0F, 0xB2, 0xD2, 0x45, 0x21, 0x4E, 0x2D, 0xDB -}; - -static const uint8_t cw_sbox3[64] = -{ - 0xDB, 0x59, 0xF4, 0xEA, 0x95, 0x8E, 0x25, 0xD5, 0x26, 0xF2, 0xDA, 0x1A, 0x4B, 0xA8, 0x08, 0x25, - 0x46, 0x16, 0x6B, 0xBF, 0xAB, 0xE0, 0xD4, 0x1B, 0x89, 0x05, 0x34, 0xE5, 0x74, 0x7B, 0xBB, 0x44, - 0xA9, 0xC6, 0x18, 0xBD, 0xE6, 0x01, 0x69, 0x5A, 0x99, 0xE0, 0x87, 0x61, 0x56, 0x35, 0x76, 0x8E, - 0xF7, 0xE8, 0x84, 0x13, 0x04, 0x7B, 0x9B, 0xA6, 0x7A, 0x1F, 0x6B, 0x5C, 0xA9, 0x86, 0x54, 0xF9 -}; - -static const uint8_t cw_sbox4[64] = -{ - 0xBC, 0xC1, 0x41, 0xFE, 0x42, 0xFB, 0x3F, 0x10, 0xB5, 0x1C, 0xA6, 0xC9, 0xCF, 0x26, 0xD1, 0x3F, - 0x02, 0x3D, 0x19, 0x20, 0xC1, 0xA8, 0xBC, 0xCF, 0x7E, 0x92, 0x4B, 0x67, 0xBC, 0x47, 0x62, 0xD0, - 0x60, 0x9A, 0x9E, 0x45, 0x79, 0x21, 0x89, 0xA9, 0xC3, 0x64, 0x74, 0x9A, 0xBC, 0xDB, 0x43, 0x66, - 0xDF, 0xE3, 0x21, 0xBE, 0x1E, 0x16, 0x73, 0x5D, 0xA2, 0xCD, 0x8C, 0x30, 0x67, 0x34, 0x9C, 0xCB -}; - -static const uint8_t AND_bit1[8] = { 0x00, 0x40, 0x04, 0x80, 0x21, 0x10, 0x02, 0x08 }; -static const uint8_t AND_bit2[8] = { 0x80, 0x08, 0x01, 0x40, 0x04, 0x20, 0x10, 0x02 }; -static const uint8_t AND_bit3[8] = { 0x82, 0x40, 0x01, 0x10, 0x00, 0x20, 0x04, 0x08 }; -static const uint8_t AND_bit4[8] = { 0x02, 0x10, 0x04, 0x40, 0x80, 0x08, 0x01, 0x20 }; - -static void swap_key(uint8_t *key) -{ - uint8_t k[8]; - memcpy(k, key, 8); - memcpy(key, key + 8, 8); - memcpy(key + 8, k, 8); -} - -static void swap_data(uint8_t *k) -{ - uint8_t d[4]; - memcpy(d, k + 4, 4); - memcpy(k + 4, k, 4); - memcpy(k, d, 4); -} - -static void des_round(uint8_t *d, uint8_t *k) -{ - uint8_t aa[44] = - { - 1, 0, 3, 1, 2, 2, 3, 2, 1, 3, 1, 1, 3, 0, 1, 2, 3, 1, 3, 2, 2, 0, - 7, 6, 5, 4, 7, 6, 5, 7, 6, 5, 6, 7, 5, 7, 5, 7, 6, 6, 7, 5, 4, 4 - }; - - uint8_t bb[44] = - { - 0x80, 0x08, 0x10, 0x02, 0x08, 0x40, 0x01, 0x20, 0x40, 0x80, 0x04, - 0x10, 0x04, 0x01, 0x01, 0x02, 0x20, 0x20, 0x02, 0x01, 0x80, 0x04, - 0x02, 0x02, 0x08, 0x02, 0x10, 0x80, 0x01, 0x20, 0x08, 0x80, 0x01, - 0x08, 0x40, 0x01, 0x02, 0x80, 0x10, 0x40, 0x40, 0x10, 0x08, 0x01 - }; - - uint8_t ff[4] = { 0x02, 0x10, 0x04, 0x04}; - uint8_t l[24] = { 0, 2, 4, 6, 7, 5, 3, 1, 4, 5, 6, 7, 7, 6, 5, 4, 7, 4, 5, 6, 4, 7, 6, 5 }; - - uint8_t des_td[8], i, o, n, c = 1, m = 0, r = 0; - uint8_t *a = aa, *b = bb, *f = ff, *p1 = l, *p2 = l + 8, *p3 = l + 16; - - for (m = 0; m < 2; m++) - { - for (i = 0; i < 4; i++) - { - des_td[*p1++] = (m) ? ((d[*p2++] * 2) & 0x3F) | ((d[*p3++] & 0x80) ? 0x01 : 0x00) : - (d[*p2++] / 2) | ((d[*p3++] & 0x01) ? 0x80 : 0x00); - } - } - - for (i = 0; i < 8; i++) - { - c = (c) ? 0 : 1; - r = (c) ? 6 : 7; - n = (i) ? i - 1 : 1; - o = (c) ? ((k[n] & *f++) ? 1 : 0) : des_td[n]; - - for (m = 1; m < r; m++) - { - o = (c) ? (o * 2) | ((k[*a++] & *b++) ? 0x01 : 0x00) : (o / 2) | ((k[*a++] & *b++) ? 0x80 : 0x00); - } - - n = (i) ? n + 1 : 0; - des_td[n] = (c) ? des_td[n] ^ o : (o ^ des_td[n]) / 4; - } - - for (i = 0; i < 8; i++) - { - d[0] ^= (AND_bit1[i] & cw_sbox1[des_td[i]]); - d[1] ^= (AND_bit2[i] & cw_sbox2[des_td[i]]); - d[2] ^= (AND_bit3[i] & cw_sbox3[des_td[i]]); - d[3] ^= (AND_bit4[i] & cw_sbox4[des_td[i]]); - } - - swap_data(d); -} - -static void cw_48_key(uint8_t *inkey, uint8_t *outkey, uint8_t algotype) -{ - uint8_t round_counter, i = 8; - uint8_t *key128 = inkey; - uint8_t *key48 = inkey + 0x10; - - round_counter = 7 - (algotype & 7); - - memset(outkey, 0, 16); - memcpy(outkey, key48, 6); - - for ( ; i > round_counter; i--) - { - if (i > 1) - { - outkey[i - 2] = key128[i]; - } - } -} - -static void ls_des_key(uint8_t *key, uint8_t rotate_counter) -{ - uint8_t i, n; - uint8_t rnd[] = { 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 1 }; - uint16_t k[8]; - - n = rnd[rotate_counter]; - - for (i = 0; i < 8; i++) - { - k[i] = key[i]; - } - - for (i = 1; i < n + 1; i++) - { - k[7] = (k[7] * 2) | ((k[4] & 0x008) ? 1 : 0); - k[6] = (k[6] * 2) | ((k[7] & 0xF00) ? 1 : 0); - k[7] &= 0xFF; - - k[5] = (k[5] * 2) | ((k[6] & 0xF00) ? 1 : 0); - k[6] &= 0xFF; - - k[4] = ((k[4] * 2) | ((k[5] & 0xF00) ? 1 : 0)) & 0xFF; - k[5] &= 0xFF; - - k[3] = (k[3] * 2) | ((k[0] & 0x008) ? 1 : 0); - k[2] = (k[2] * 2) | ((k[3] & 0xF00) ? 1 : 0); - k[3] &= 0xFF; - - k[1] = (k[1] * 2) | ((k[2] & 0xF00) ? 1 : 0); - k[2] &= 0xFF; - - k[0] = ((k[0] * 2) | ((k[1] & 0xF00) ? 1 : 0)) & 0xFF; - k[1] &= 0xFF; - } - - for (i = 0; i < 8; i++) - { - key[i] = (uint8_t) k[i]; - } -} - -static void rs_des_key(uint8_t *k, uint8_t rotate_counter) -{ - uint8_t i, c; - - for (i = 1; i < rotate_counter + 1; i++) - { - c = (k[3] & 0x10) ? 0x80 : 0; - k[3] /= 2; - - if (k[2] & 1) - { - k[3] |= 0x80; - } - - k[2] /= 2; - - if (k[1] & 1) - { - k[2] |= 0x80; - } - - k[1] /= 2; - - if (k[0] & 1) - { - k[1] |= 0x80; - } - - k[0] /= 2; - k[0] |= c ; - c = (k[7] & 0x10) ? 0x80 : 0; - k[7] /= 2; - - if (k[6] & 1) - { - k[7] |= 0x80; - } - - k[6] /= 2; - - if (k[5] & 1) - { - k[6] |= 0x80; - } - - k[5] /= 2; - - if (k[4] & 1) - { - k[5] |= 0x80; - } - - k[4] /= 2; - k[4] |= c; - } -} - -static void rs_des_subkey(uint8_t *k, uint8_t rotate_counter) -{ - uint8_t rnd[] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; - - rs_des_key(k, rnd[rotate_counter]); -} - -static void prep_key(uint8_t *key) -{ - int32_t round_counter = 6, i, a; - uint8_t DES_key[8], j; - - key[7] = 6; - memset(DES_key, 0, 8); - - do - { - a = 7; - i = key[7]; - j = key[round_counter]; - - do - { - DES_key[i] = ( (DES_key[i] * 2) | ((j & 1) ? 1 : 0) ) & 0xFF; - - j /= 2; - i--; - - if (i < 0) - { - i = 6; - } - a--; - } - while (a >= 0); - - key[7] = i; - round_counter--; - } - while (round_counter >= 0); - - a = DES_key[4]; - DES_key[4] = DES_key[6]; - DES_key[6] = a; - DES_key[7] = (DES_key[3] * 16) & 0xFF; - - memcpy(key, DES_key, 8); - rs_des_key(key, 4); -} - -static void l2_des(uint8_t *data, uint8_t *key, uint8_t algo) -{ - uint8_t i, k0[22], k1[22]; - - memcpy(k0, key, 22); - memcpy(k1, key, 22); - - cw_48_key(k0, k1, algo); - prep_key(k1); - - for (i = 0; i < 2; i++) - { - ls_des_key(k1, 15); - des_round(data, k1); - } -} - -static void r2_des(uint8_t *data, uint8_t *key, uint8_t algo) -{ - uint8_t i, k0[22], k1[22]; - - memcpy(k0, key, 22); - memcpy(k1, key, 22); - - cw_48_key(k0, k1, algo); - prep_key(k1); - - for (i = 0; i < 2; i++) - { - ls_des_key(k1, 15); - } - - for (i = 0; i < 2; i++) - { - des_round(data, k1); - rs_des_subkey(k1, 1); - } - - swap_data(data); -} - -static void cw_des(uint8_t *data, uint8_t *inkey, uint8_t m) -{ - uint8_t key[22], i; - - memcpy(key, inkey + 9, 8); - prep_key(key); - - for (i = 16; i > 0; i--) - { - if (m == 1) - { - ls_des_key(key, (uint8_t) (i - 1)); - } - - des_round( data ,key); - - if (m == 0) - { - rs_des_subkey(key, (uint8_t) (i - 1)); - } - } -} - -static void cw_dec_enc(uint8_t *d, uint8_t *k, uint8_t a, uint8_t m) -{ - uint8_t n = m & 1; - - l2_des(d, k, a); - cw_des(d, k, n); - r2_des(d, k, a); - - if (m & 2) - { - swap_key(k); - } -} - -static uint8_t process_nano80(uint8_t *data, uint32_t caid, int32_t provider, uint8_t *opKey, - uint8_t nanoLength, uint8_t nano80Algo) -{ - int32_t i, j; - uint8_t key[16], desKey[16], t[8], dat1[8], dat2[8], k0D00C000[16]; - - if (nanoLength < 11) - { - return 0; - } - - if (caid == 0x0D00 && provider != 0xA0 && !get_key(k0D00C000, 0x0D00C0, 0, 16, 1)) - { - return 0; - } - - if (nano80Algo > 1) - { - return 0; - } - - memset(t, 0, 8); - memcpy(dat1, data, 8); - - if(caid == 0x0D00 && provider != 0xA0) - { - memcpy(key, k0D00C000, 16); - } - else - { - memcpy(key, opKey, 16); - } - - des_ecb3_decrypt(data, key); - memcpy(desKey, data, 8); - memcpy(data, dat1, 8); - - if (caid == 0x0D00 && provider != 0xA0) - { - memcpy(key, &k0D00C000[8], 8); - memcpy(&key[8], k0D00C000, 8); - } - else - { - memcpy(key, &opKey[8], 8); - memcpy(&key[8], opKey, 8); - } - - des_ecb3_decrypt(data, key); - memcpy(&desKey[8], data, 8); - - for (i = 8; i + 7 < nanoLength; i += 8) - { - memcpy(dat1, &data[i], 8); - memcpy(dat2, dat1, 8); - memcpy(key, desKey, 16); - des_ecb3_decrypt(dat1, key); - - for (j = 0; j < 8; j++) - { - dat1[j] ^= t[j]; - } - - memcpy(&data[i], dat1, 8); - memcpy(t, dat2, 8); - } - - return data[10] + 5; -} - -static void cryptoworks_signature(const uint8_t *data, uint32_t length, uint8_t *key, uint8_t *signature) -{ - uint32_t i, sigPos; - int8_t algo, first; - - algo = data[0] & 7; - if (algo == 7) - { - algo = 6; - } - - memset(signature, 0, 8); - first = 1; - sigPos = 0; - - for (i = 0; i < length; i++) - { - signature[sigPos] ^= data[i]; - sigPos++; - - if (sigPos > 7) - { - if (first) - { - l2_des(signature, key, algo); - } - - cw_des(signature, key, 1); - - sigPos = 0; - first = 0; - } - } - - if (sigPos > 0) - { - cw_des(signature, key, 1); - } - - r2_des(signature, key, algo); -} - -static void decrypt_des(uint8_t *data, uint8_t algo, uint8_t *key) -{ - int32_t i; - uint8_t k[22], t[8]; - - algo &= 7; - - if (algo < 7) - { - cw_dec_enc(data, key, algo, 0); - } - else - { - memcpy(k, key, 22); - - for (i = 0; i < 3; i++) - { - cw_dec_enc(data, k, algo, i & 1); - - memcpy(t, k, 8); - memcpy(k, k + 8, 8); - memcpy(k + 8, t, 8); - } - } -} - -int8_t cryptoworks_ecm(uint32_t caid, uint8_t *ecm, uint8_t *cw) -{ - int32_t provider = -1; - uint8_t keyIndex = 0, nanoLength, newEcmLength, key[22], signature[8], nano80Algo = 1; - uint16_t i, j, ecmLen = SCT_LEN(ecm); - uint32_t ident; - - if (ecmLen < 8) - { - return EMU_NOT_SUPPORTED; - } - - if (ecm[7] != ecmLen - 8) - { - return EMU_NOT_SUPPORTED; - } - - memset(key, 0, 22); - - for (i = 8; i + 1 < ecmLen; i += ecm[i + 1] + 2) - { - if (ecm[i] == 0x83 && i + 2 < ecmLen) - { - provider = ecm[i + 2] & 0xFC; - keyIndex = ecm[i + 2] & 3; - keyIndex = keyIndex ? 1 : 0; - } - else if (ecm[i] == 0x84 && i + 3 < ecmLen) - { - //nano80Provider = ecm[i + 2] & 0xFC; - //nano80KeyIndex = ecm[i + 2] & 3; - //nano80KeyIndex = nano80KeyIndex ? 1 : 0; - nano80Algo = ecm[i + 3]; - } - } - - if (provider < 0) - { - switch (caid) - { - case 0x0D00: - provider = 0xC0; - break; - - case 0x0D02: - provider = 0xA0; - break; - - case 0x0D03: - provider = 0x04; - break; - - case 0x0D05: - provider = 0x04; - break; - - default: - return EMU_NOT_SUPPORTED; - } - } - - ident = (caid << 8) | provider; - - if (!get_key(key, ident, keyIndex, 16, 1)) - { - return EMU_KEY_NOT_FOUND; - } - - if (!get_key(&key[16], ident, 6, 6, 1)) - { - return EMU_KEY_NOT_FOUND; - } - - for (i = 8; i + 1 < ecmLen; i += ecm[i + 1] + 2) - { - if (ecm[i] == 0x80 && i + 2 + 7 < ecmLen && i + 2 + ecm[i + 1] <= ecmLen && - (provider == 0xA0 || provider == 0xC0 || provider == 0xC4 || provider == 0xC8)) - { - nanoLength = ecm[i + 1]; - newEcmLength = process_nano80(ecm + i + 2, caid, provider, key, nanoLength, nano80Algo); - - if (newEcmLength == 0 || newEcmLength > ecmLen - (i + 2 + 3)) - { - return EMU_NOT_SUPPORTED; - } - - ecm[i + 2 + 3] = 0x81; - ecm[i + 2 + 4] = 0x70; - ecm[i + 2 + 5] = newEcmLength; - ecm[i + 2 + 6] = 0x81; - ecm[i + 2 + 7] = 0xFF; - - return cryptoworks_ecm(caid, ecm + i + 2 + 3, cw); - } - } - - if (ecmLen - 15 < 1) - { - return EMU_NOT_SUPPORTED; - } - - cryptoworks_signature(ecm + 5, ecmLen - 15, key, signature); - - for (i = 8; i + 1 < ecmLen; i += ecm[i + 1] + 2) - { - switch (ecm[i]) - { - case 0xDA: - case 0xDB: - case 0xDC: - if (i + 2 + ecm[i + 1] > ecmLen) - { - break; - } - for (j = 0; j + 7 < ecm[i + 1]; j += 8) - { - decrypt_des(&ecm[i + 2 + j], ecm[5], key); - } - break; - - case 0xDF: - if (i + 2 + 8 > ecmLen) - { - break; - } - if (memcmp(&ecm[i + 2], signature, 8)) - { - return EMU_CHECKSUM_ERROR; - } - break; - } - } - - for (i = 8; i + 1 < ecmLen; i += ecm[i + 1] + 2) - { - switch (ecm[i]) - { - case 0xDB: - if (i + 2 + ecm[i + 1] <= ecmLen && ecm[i + 1] == 16) - { - memcpy(cw, &ecm[i + 2], 16); - return EMU_OK; - } - break; - } - } - - return EMU_CW_NOT_FOUND; -} - -#endif // WITH_EMU diff --git a/module-emulator-cryptoworks.h b/module-emulator-cryptoworks.h deleted file mode 100755 index c2424e2..0000000 --- a/module-emulator-cryptoworks.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef MODULE_EMULATOR_CRYPTOWORKS_H -#define MODULE_EMULATOR_CRYPTOWORKS_H - -#ifdef WITH_EMU - -int8_t cryptoworks_ecm(uint32_t caid, uint8_t *ecm, uint8_t *cw); - -#endif // WITH_EMU - -#endif // MODULE_EMULATOR_CRYPTOWORKS_H diff --git a/module-emulator-director.c b/module-emulator-director.c deleted file mode 100755 index c8c28b9..0000000 --- a/module-emulator-director.c +++ /dev/null @@ -1,644 +0,0 @@ -#define MODULE_LOG_PREFIX "emu" - -#include "globals.h" - -#ifdef WITH_EMU - -#include "cscrypt/des.h" -#include "module-emulator-osemu.h" -#include "oscam-aes.h" -#include "oscam-string.h" - -/*************************************************************************************************/ - -// Shared functions - -static uint16_t calculate_checksum(uint8_t *data, uint8_t length) -{ - /* - * ECM and EMM checksum calculation - * 1. Combine data in 2 byte groups - * 2. Add them together - * 3. Multiply result by itself (power of 7) - * 4. XOR with fixed value 0x17E3 - */ - - uint8_t i; - uint16_t checksum = 0; - - for (i = 0; i < length; i += 2) - { - checksum += (data[i] << 8) | data[i + 1]; - } - - checksum = checksum * checksum * checksum * checksum * checksum * checksum * checksum; - checksum ^= 0x17E3; - - return checksum; -} - -static inline int8_t get_key(uint32_t keyIndex, char *keyName, uint8_t *key, uint32_t keyLength) -{ - /* - * keyIndex meaning for: - * ecm keys --> entitlementId - * emm keys --> aeskeyIndex - * aes keys --> keyIndex - * - * keyName meaning for: - * ecm keys --> "01" - * emm keys --> "MK" or "MK01" - * aes keys --> "AES" - */ - - return emu_find_key('T', keyIndex, 0, keyName, key, keyLength, 1, 0, 0, NULL); -} - -/*************************************************************************************************/ - -/* - * Director ECM emulator - * Supported versions: v4, v5, v6 (not working correctly) -*/ - -int8_t director_ecm(uint8_t *ecm, uint8_t *dw) -{ - uint8_t nanoType, nanoLength; - uint8_t *nanoData; - uint32_t pos = 3; - uint32_t entitlementId; - uint32_t ks[32]; - uint8_t ecmKey[8]; - uint16_t ecmLen = SCT_LEN(ecm); - - if (ecmLen < 5) - { - return EMU_NOT_SUPPORTED; - } - - do - { - nanoType = ecm[pos]; - nanoLength = ecm[pos + 1]; - - if (pos + 2 + nanoLength > ecmLen) - { - break; - } - - nanoData = ecm + pos + 2; - - // ECM validation - uint16_t payloadChecksum = (nanoData[nanoLength - 2] << 8) | nanoData[nanoLength - 1]; - uint16_t calculatedChecksum = calculate_checksum(nanoData, nanoLength - 2); - - if (calculatedChecksum != payloadChecksum) - { - cs_log_dbg(D_READER, "ECM checksum error (%.4X instead of %.4X)", calculatedChecksum, payloadChecksum); - return EMU_CHECKSUM_ERROR; - } - // End of ECM validation - - switch (nanoType) - { - case 0xEC: // Director v6 (September 2017) - { - if (nanoLength != 0x28) - { - cs_log_dbg(D_READER, "WARNING: nanoType EC length (%d) != %d", nanoLength, 0x28); - break; - } - - entitlementId = b2i(4, nanoData); - cs_log_dbg(D_READER, "INFO: Using entitlement id %.4X", entitlementId); - - if (!get_key(entitlementId, "01", ecmKey, 8)) - { - return EMU_KEY_NOT_FOUND; - } - - // Step 1 - Decrypt DES CBC with ecmKey and iv = { 0 } (equal to nanoED) - uint8_t encryptedData[32] = { 0 }; - memcpy(encryptedData, nanoData + 6, 32); - - uint8_t iv[8] = { 0 }; - des_cbc_decrypt(encryptedData, iv, ecmKey, 32); - - uint8_t nanoMode = nanoData[5]; - - if ((nanoMode & 0x20) == 0) // Old algo - { - // Step 2 - Create CW (equal to nano ED) - dw[0] = encryptedData[0x05]; - dw[1] = encryptedData[0x19]; - dw[2] = encryptedData[0x1D]; - dw[3] = (dw[0] + dw[1] + dw[2]) & 0xFF; - dw[4] = encryptedData[0x0B]; - dw[5] = encryptedData[0x12]; - dw[6] = encryptedData[0x1A]; - dw[7] = (dw[4] + dw[5] + dw[6]) & 0xFF; - dw[8] = encryptedData[0x16]; - dw[9] = encryptedData[0x03]; - dw[10] = encryptedData[0x11]; - dw[11] = (dw[8] + dw[9] + dw[10]) & 0xFF; - dw[12] = encryptedData[0x18]; - dw[13] = encryptedData[0x10]; - dw[14] = encryptedData[0x0E]; - dw[15] = (dw[12] + dw[13] + dw[14]) & 0xFF; - - return EMU_OK; - } - else // New algo (overencryption with AES) - { - // Step 2 - Prepare data for AES (it is like the creation of CW in nanoED but swapped each 8 bytes) - uint8_t dataEC[16] = { 0 }; - - dataEC[0] = encryptedData[0x02]; - dataEC[1] = encryptedData[0x0E]; - dataEC[2] = encryptedData[0x10]; - dataEC[3] = encryptedData[0x18]; - dataEC[4] = encryptedData[0x09]; - dataEC[5] = encryptedData[0x11]; - dataEC[6] = encryptedData[0x03]; - dataEC[7] = encryptedData[0x16]; - - dataEC[8] = encryptedData[0x13]; - dataEC[9] = encryptedData[0x1A]; - dataEC[10] = encryptedData[0x12]; - dataEC[11] = encryptedData[0x0B]; - dataEC[12] = encryptedData[0x04]; - dataEC[13] = encryptedData[0x1D]; - dataEC[14] = encryptedData[0x19]; - dataEC[15] = encryptedData[0x05]; - - // Step 3 - Decrypt AES CBC with new aesKey and iv 2EBD816A5E749A708AE45ADDD84333DE - uint8_t aesKeyIndex = nanoMode & 0x1F; // 32 possible AES keys - uint8_t aesKey[16] = { 0 }; - - char tmpBuffer[33]; - cs_hexdump(0, aesKey, 16, tmpBuffer, sizeof(tmpBuffer)); - cs_log_dbg(D_READER, "INFO: Using AES key index: %02X, value: %s", aesKeyIndex, tmpBuffer); - - if (!get_key(aesKeyIndex, "AES", aesKey, 16)) - { - return EMU_KEY_NOT_FOUND; - } - - struct aes_keys aes; - aes_set_key(&aes, (char *)aesKey); - - uint8_t ivAes[16] = { 0x2E, 0xBD, 0x81, 0x6A, 0x5E, 0x74, 0x9A, 0x70, 0x8A, 0xE4, 0x5A, 0xDD, 0xD8, 0x43, 0x33, 0xDE }; - aes_cbc_decrypt(&aes, dataEC, 16, ivAes); - - // Step 4 - Create CW (a simple swap) - uint8_t offset; - for (offset = 0; offset < 16; offset++) - { - dw[offset] = dataEC[15 - offset]; - } - - return EMU_OK; - } - } - - case 0xED: // Director v5 (September 2016) - { - if (nanoLength != 0x26) - { - cs_log_dbg(D_READER, "WARNING: nanoType ED length (%d) != %d", nanoLength, 0x26); - break; - } - - entitlementId = b2i(4, nanoData); - cs_log_dbg(D_READER, "INFO: Using entitlement id %.4X", entitlementId); - - if (!get_key(entitlementId, "01", ecmKey, 8)) - { - return EMU_KEY_NOT_FOUND; - } - - uint8_t encryptedData[32] = { 0 }; - memcpy(encryptedData, nanoData + 4, 32); - - uint8_t iv[8] = { 0 }; - des_cbc_decrypt(encryptedData, iv, ecmKey, 32); - - dw[0] = encryptedData[0x05]; - dw[1] = encryptedData[0x19]; - dw[2] = encryptedData[0x1D]; - dw[3] = (dw[0] + dw[1] + dw[2]) & 0xFF; - dw[4] = encryptedData[0x0B]; - dw[5] = encryptedData[0x12]; - dw[6] = encryptedData[0x1A]; - dw[7] = (dw[4] + dw[5] + dw[6]) & 0xFF; - dw[8] = encryptedData[0x16]; - dw[9] = encryptedData[0x03]; - dw[10] = encryptedData[0x11]; - dw[11] = (dw[8] + dw[9] + dw[10]) & 0xFF; - dw[12] = encryptedData[0x18]; - dw[13] = encryptedData[0x10]; - dw[14] = encryptedData[0x0E]; - dw[15] = (dw[12] + dw[13] + dw[14]) & 0xFF; - - return EMU_OK; - } - - case 0xEE: // Director v4 - { - if (nanoLength != 0x16) - { - cs_log_dbg(D_READER, "WARNING: nanoType EE length (%d) != %d", nanoLength, 0x16); - break; - } - - entitlementId = b2i(4, nanoData); - cs_log_dbg(D_READER, "INFO: Using entitlement id %.4X", entitlementId); - - if (!get_key(entitlementId, "01", ecmKey, 8)) - { - return EMU_KEY_NOT_FOUND; - } - - memcpy(dw, nanoData + 4 + 8, 8); // even - memcpy(dw + 8, nanoData + 4, 8); // odd - - des_set_key(ecmKey, ks); - - des(dw, ks, 0); - des(dw + 8, ks, 0); - - dw[3] = (dw[0] + dw[1] + dw[2]) & 0xFF; - dw[7] = (dw[4] + dw[5] + dw[6]) & 0xFF; - dw[11] = (dw[8] + dw[9] + dw[10]) & 0xFF; - dw[15] = (dw[12] + dw[13] + dw[14]) & 0xFF; - - return EMU_OK; - } - - default: - cs_log_dbg(D_READER, "WARNING: nanoType %.2X not supported", nanoType); - return EMU_NOT_SUPPORTED; - } - - pos += 2 + nanoLength; - - } while (pos < ecmLen); - - return EMU_NOT_SUPPORTED; -} - -/*************************************************************************************************/ - -/* - * Director EMM emulator - * Supported versions: v4, v5, v6 (same as v5) -*/ - -static const uint8_t MixTable[] = -{ - 0x12, 0x78, 0x4B, 0x19, 0x13, 0x80, 0x2F, 0x84, 0x86, 0x4C, 0x09, 0x53, 0x15, 0x79, 0x6B, 0x49, - 0x10, 0x4D, 0x33, 0x43, 0x18, 0x37, 0x83, 0x38, 0x82, 0x1B, 0x6E, 0x24, 0x2A, 0x85, 0x3C, 0x3D, - 0x5A, 0x58, 0x55, 0x5D, 0x20, 0x41, 0x65, 0x51, 0x0C, 0x45, 0x63, 0x7F, 0x0F, 0x46, 0x21, 0x7C, - 0x2C, 0x61, 0x7E, 0x0A, 0x42, 0x57, 0x35, 0x16, 0x87, 0x3B, 0x4F, 0x40, 0x34, 0x22, 0x26, 0x74, - 0x32, 0x69, 0x44, 0x7A, 0x6A, 0x6D, 0x0D, 0x56, 0x23, 0x2B, 0x5C, 0x72, 0x76, 0x36, 0x28, 0x25, - 0x2E, 0x52, 0x5B, 0x6C, 0x7D, 0x30, 0x0B, 0x5E, 0x47, 0x1F, 0x7B, 0x31, 0x3E, 0x11, 0x77, 0x1E, - 0x60, 0x75, 0x54, 0x27, 0x50, 0x17, 0x70, 0x59, 0x1A, 0x2D, 0x4A, 0x67, 0x3A, 0x5F, 0x68, 0x08, - 0x4E, 0x3F, 0x29, 0x6F, 0x81, 0x71, 0x39, 0x64, 0x48, 0x66, 0x73, 0x14, 0x0E, 0x1D, 0x62, 0x1C -}; - -/* -static void rotate_bytes(uint8_t *in, int8_t n) -{ - if (n > 1) - { - uint8_t *e = in + n - 1; - do - { - uint8_t temp = *in; - *in++ = *e; - *e-- = temp; - } - while (in < e); - } -} -*/ - -static void decrypt_ecm_key(uint8_t *emmKey, uint8_t *tagData, uint8_t *ecmKey) -{ - uint8_t temp, *e, *payLoad, iv[8] = { 0 }; - - //rotate_bytes(emmKey, 8); - - e = emmKey + 8 - 1; - do - { - temp = *emmKey; - *emmKey++ = *e; - *e-- = temp; - } - while (emmKey < e); - - payLoad = tagData + 4 + 5; - des_cbc_decrypt(payLoad, iv, emmKey, 16); - - ecmKey[0] = payLoad[0x0F]; - ecmKey[1] = payLoad[0x01]; - ecmKey[2] = payLoad[0x0B]; - ecmKey[3] = payLoad[0x03]; - ecmKey[4] = payLoad[0x0E]; - ecmKey[5] = payLoad[0x04]; - ecmKey[6] = payLoad[0x0A]; - ecmKey[7] = payLoad[0x08]; -} - -static int8_t parse_emm_nano_tags(uint8_t *data, uint32_t length, uint8_t keyIndex, uint32_t *keysAdded) -{ - uint8_t tagType, tagLength, *tagData, blockIndex, emmKey[8], tagDataDecrypted[16][8]; - uint32_t pos = 0, entitlementId, ks[32]; - int32_t i, k; - char keyValue[17]; - - if (length < 2) - { - return EMU_NOT_SUPPORTED; - } - - while (pos < length) - { - tagType = data[pos]; - tagLength = data[pos+1]; - - if (pos + 2 + tagLength > length) - { - return EMU_CORRUPT_DATA; - } - - tagData = data + pos + 2; - - switch (tagType) - { - case 0xE4: // EMM_TAG_SECURITY_TABLE_DESCRIPTOR (ram emm keys) - { - uint8_t tagMode = data[pos + 2]; - - switch (tagMode) - { - case 0x01: // keySet 01 (MK01) - { - if (tagLength != 0x8A) - { - cs_log_dbg(D_READER, "WARNING: nanoTag E4 length (%d) != %d", tagLength, 0x8A); - return EMU_NOT_SUPPORTED; - } - - if (!get_key(keyIndex, "MK01", emmKey, 8)) - { - return EMU_KEY_NOT_FOUND; - } - - uint8_t iv[8] = { 0 }; - uint8_t *tagPayload = tagData + 2; - des_cbc_decrypt(tagPayload, iv, emmKey, 136); - - for (k = 0; k < 16; k++) // loop 16 keys - { - for (i = 0; i < 8; i++) // loop 8 bytes of key - { - tagDataDecrypted[k][i] = tagPayload[MixTable[8 * k + i]]; - } - } - - blockIndex = tagData[1] & 0x03; - - SAFE_MUTEX_LOCK(&emu_key_data_mutex); - for (i = 0; i < 16; i++) - { - emu_set_key('T', (blockIndex << 4) + i, "MK01", tagDataDecrypted[i], 8, 0, NULL, NULL); - } - SAFE_MUTEX_UNLOCK(&emu_key_data_mutex); - } - break; - - case 0xFF: // keySet FF (MK) - { - if (tagLength != 0x82) - { - cs_log_dbg(D_READER, "WARNING: nanoTag E4 length (%d) != %d", tagLength, 0x82); - return EMU_NOT_SUPPORTED; - } - - if (!get_key(keyIndex, "MK", emmKey, 8)) - { - return EMU_KEY_NOT_FOUND; - } - - des_set_key(emmKey, ks); - - for (i = 0; i < 16; i++) - { - des(tagData + 2 + (i * 8), ks, 0); - } - - blockIndex = tagData[1] & 0x03; - - SAFE_MUTEX_LOCK(&emu_key_data_mutex); - for (i = 0; i < 16; i++) - { - emu_set_key('T', (blockIndex << 4) + i, "MK", tagData + 2 + (i * 8), 8, 0, NULL, NULL); - } - SAFE_MUTEX_UNLOCK(&emu_key_data_mutex); - } - break; - - default: - cs_log_dbg(D_READER, "WARNING: nanoTag E4 mode %.2X not supported", tagMode); - return EMU_NOT_SUPPORTED; - } - break; - } - - case 0xE1: // EMM_TAG_EVENT_ENTITLEMENT_DESCRIPTOR (ecm keys) - { - uint8_t tagMode = data[pos + 2 + 4]; - - switch (tagMode) - { - case 0x00: // ecm keys from mode FF - { - if (tagLength != 0x12) - { - cs_log_dbg(D_READER, "WARNING: nanoTag E1 length (%d) != %d", tagLength, 0x12); - return EMU_NOT_SUPPORTED; - } - - entitlementId = b2i(4, tagData); - - if (!get_key(keyIndex, "MK", emmKey, 8)) - { - return EMU_KEY_NOT_FOUND; - } - - des_set_key(emmKey, ks); - des(tagData + 4 + 5, ks, 0); - uint8_t ecmKeyChk[1] = { 0 }; - memcpy(ecmKeyChk, tagData + 4 + 5 + 7, 1); - - if (ecmKeyChk[0] != 0x00) // check if key looks valid (last byte 0x00) - { - cs_log_dbg(D_READER, "Key rejected from EMM (looks invalid)"); - return EMU_KEY_REJECTED; - } - - SAFE_MUTEX_LOCK(&emu_key_data_mutex); - if (emu_update_key('T', entitlementId, "01", tagData + 4 + 5, 8, 1, NULL)) - { - (*keysAdded)++; - cs_hexdump(0, tagData + 4 + 5, 8, keyValue, sizeof(keyValue)); - cs_log("Key found in EMM: T %.8X 01 %s", entitlementId, keyValue); - } - SAFE_MUTEX_UNLOCK(&emu_key_data_mutex); - } - break; - - case 0x01: // ecm keys from mode 01 - { - if (tagLength != 0x1A) - { - cs_log_dbg(D_READER, "WARNING: nanoTag E1 length (%d) != %d", tagLength, 0x1A); - return EMU_NOT_SUPPORTED; - } - - entitlementId = b2i(4, tagData); - - if (!get_key(keyIndex, "MK01", emmKey, 8)) - { - return EMU_KEY_NOT_FOUND; - } - - uint8_t ecmKey[8] = { 0 }; - decrypt_ecm_key(emmKey, tagData, ecmKey); - - if (ecmKey[7] != 0x00) // check if key looks valid (last byte 0x00) - { - cs_log_dbg(D_READER, "Key rejected from EMM (looks invalid)"); - return EMU_KEY_REJECTED; - } - - SAFE_MUTEX_LOCK(&emu_key_data_mutex); - if (emu_update_key('T', entitlementId, "01", ecmKey, 8, 1, NULL)) - { - (*keysAdded)++; - cs_hexdump(0, ecmKey, 8, keyValue, sizeof(keyValue)); - cs_log("Key found in EMM: T %.8X 01 %s", entitlementId, keyValue); - } - SAFE_MUTEX_UNLOCK(&emu_key_data_mutex); - } - break; - - default: - cs_log_dbg(D_READER, "WARNING: nanoTag E1 mode %.2X not supported", tagMode); - return EMU_NOT_SUPPORTED; - } - break; - } - - default: - cs_log_dbg(D_READER, "WARNING: nanoTag %.2X not supported", tagType); - return EMU_NOT_SUPPORTED; - } - - pos += 2 + tagLength; - } - - return EMU_OK; -} - -static int8_t parse_emm_nano_data(uint8_t *data, uint32_t *nanoLength, uint32_t maxLength, - uint8_t keyIndex, uint32_t *keysAdded) -{ - uint32_t pos = 0; - uint16_t sectionLength; - int8_t ret = EMU_OK; - - if (maxLength < 2) - { - (*nanoLength) = 0; - return EMU_NOT_SUPPORTED; - } - - sectionLength = ((data[pos] << 8) | data[pos + 1]) & 0x0FFF; - - if (pos + 2 + sectionLength > maxLength) - { - (*nanoLength) = pos; - return EMU_CORRUPT_DATA; - } - - ret = parse_emm_nano_tags(data + pos + 2, sectionLength, keyIndex, keysAdded); - - pos += 2 + sectionLength; - - (*nanoLength) = pos; - return ret; -} - -int8_t director_emm(uint8_t *emm, uint32_t *keysAdded) -{ - uint8_t keyIndex, ret = EMU_OK; - uint16_t emmLen = SCT_LEN(emm); - uint32_t pos = 3; - uint32_t permissionDataType; - uint32_t nanoLength = 0; - - while (pos < emmLen && !ret) - { - permissionDataType = emm[pos]; - - switch (permissionDataType) - { - case 0x00: - break; - - case 0x01: - pos += 0x0A; - break; - - case 0x02: - pos += 0x26; - break; - - default: - cs_log_dbg(D_READER, "ERROR: unknown permissionDataType %.2X (pos: %d)", permissionDataType, pos); - return EMU_NOT_SUPPORTED; - } - - if (pos + 6 >= emmLen) - { - return EMU_CORRUPT_DATA; - } - - keyIndex = emm[pos + 1]; - - // EMM validation - // Copy payload checksum bytes and then set them to zero, - // so they do not affect the calculated checksum. - uint16_t payloadChecksum = (emm[pos + 2] << 8) | emm[pos + 3]; - memset(emm + pos + 2, 0, 2); - uint16_t calculatedChecksum = calculate_checksum(emm + 3, emmLen - 3); - - if (calculatedChecksum != payloadChecksum) - { - cs_log_dbg(D_READER, "EMM checksum error (%.4X instead of %.4X)", calculatedChecksum, payloadChecksum); - return EMU_CHECKSUM_ERROR; - } - // End of EMM validation - - pos += 0x04; - ret = parse_emm_nano_data(emm + pos, &nanoLength, emmLen - pos, keyIndex, keysAdded); - pos += nanoLength; - } - - return ret; -} - -#endif // WITH_EMU diff --git a/module-emulator-director.h b/module-emulator-director.h deleted file mode 100755 index de430cf..0000000 --- a/module-emulator-director.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef MODULE_EMULATOR_DIRECTOR_H -#define MODULE_EMULATOR_DIRECTOR_H - -#ifdef WITH_EMU - -int8_t director_ecm(uint8_t *ecm, uint8_t *dw); -int8_t director_emm(uint8_t *emm, uint32_t *keysAdded); - -#endif // WITH_EMU - -#endif // MODULE_EMULATOR_DIRECTOR_H diff --git a/module-emulator-irdeto.c b/module-emulator-irdeto.c deleted file mode 100755 index c9df970..0000000 --- a/module-emulator-irdeto.c +++ /dev/null @@ -1,602 +0,0 @@ -#define MODULE_LOG_PREFIX "emu" - -#include "globals.h" - -#ifdef WITH_EMU - -#include "cscrypt/des.h" -#include "module-emulator-osemu.h" -#include "oscam-string.h" - -static inline void xxor(uint8_t *data, int32_t len, const uint8_t *v1, const uint8_t *v2) -{ - uint32_t i; - - switch (len) - { - case 16: - for (i = 0; i < 16; ++i) - { - data[i] = v1[i] ^ v2[i]; - } - break; - - case 8: - for (i = 0; i < 8; ++i) - { - data[i] = v1[i] ^ v2[i]; - } - break; - - case 4: - for (i = 0; i < 4; ++i) - { - data[i] = v1[i] ^ v2[i]; - } - break; - - default: - while (len--) - { - *data++ = *v1++ ^ *v2++; - } - break; - } -} - -// Irdeto EMU -static int8_t get_key(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, - uint8_t isCriticalKey, uint32_t *keyRef) -{ - char keyStr[EMU_MAX_CHAR_KEYNAME]; - - if (*keyRef > 0xFF) - { - return 0; - } - - snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); - - if (emu_find_key('I', ident, 0, keyStr, buf, 16, *keyRef > 0 ? 0 : isCriticalKey, *keyRef, 0, NULL)) - { - (*keyRef)++; - return 1; - } - - return 0; -} - -static void irdeto2_encrypt(uint8_t *data, const uint8_t *seed, const uint8_t *key, int32_t len) -{ - int32_t i; - const uint8_t *tmp = seed; - uint32_t ks1[32], ks2[32]; - - des_set_key(key, ks1); - des_set_key(key + 8, ks2); - - len &= ~7; - - for (i = 0; i + 7 < len; i += 8) - { - xxor(&data[i], 8, &data[i], tmp); - tmp = &data[i]; - des(&data[i], ks1, 1); - des(&data[i], ks2, 0); - des(&data[i], ks1, 1); - } -} - -static void irdeto2_decrypt(uint8_t *data, const uint8_t *seed, const uint8_t *key, int32_t len) -{ - int32_t i, n = 0; - uint8_t buf[2][8]; - uint32_t ks1[32], ks2[32]; - - des_set_key(key, ks1); - des_set_key(key + 8, ks2); - - len &= ~7; - - memcpy(buf[n], seed, 8); - - for (i = 0; i + 7 < len; i += 8, data += 8, n ^= 1) - { - memcpy(buf[1 - n], data, 8); - des(data, ks1, 0); - des(data, ks2, 1); - des(data, ks1, 0); - xxor(data, 8, data, buf[n]); - } -} - -static int8_t calculate_hash(const uint8_t *key, const uint8_t *iv, const uint8_t *data, int32_t len) -{ - int32_t l, y; - uint8_t cbuff[32]; - uint32_t ks1[32], ks2[32]; - - des_set_key(key, ks1); - des_set_key(key + 8, ks2); - - memset(cbuff, 0, sizeof(cbuff)); - - len -= 8; - - for (y = 0; y < len; y += 8) - { - if (y < len - 8) - { - xxor(cbuff, 8, cbuff, &data[y]); - } - else - { - l = len - y; - xxor(cbuff, l, cbuff, &data[y]); - xxor(cbuff + l, 8 - l, cbuff + l, iv + 8); - } - - des(cbuff, ks1, 1); - des(cbuff, ks2, 0); - des(cbuff, ks1, 1); - } - - return memcmp(cbuff, &data[len], 8) == 0; -} - -int8_t irdeto2_ecm(uint16_t caid, uint8_t *oecm, uint8_t *dw) -{ - uint8_t keyNr = 0, length, end, key[16], okeySeed[16], keySeed[16], keyIV[16], tmp[16]; - uint8_t ecmCopy[EMU_MAX_ECM_LEN], *ecm = oecm; - uint16_t ecmLen = SCT_LEN(ecm); - uint32_t key0Ref, keySeedRef, keyIVRef, ident, i, j, l; - - if (ecmLen < 12) - { - return EMU_NOT_SUPPORTED; - } - - length = ecm[11]; - keyNr = ecm[9]; - ident = ecm[8] | caid << 8; - - if (ecmLen < length + 12) - { - return EMU_NOT_SUPPORTED; - } - - key0Ref = 0; - - while (get_key(key, ident, '0', keyNr, 1, &key0Ref)) - { - keySeedRef = 0; - - while (get_key(okeySeed, ident, 'M', 1, 1, &keySeedRef)) - { - keyIVRef = 0; - - while (get_key(keyIV, ident, 'M', 2, 1, &keyIVRef)) - { - memcpy(keySeed, okeySeed, 16); - memcpy(ecmCopy, oecm, ecmLen); - - ecm = ecmCopy; - memset(tmp, 0, 16); - irdeto2_encrypt(keySeed, tmp, key, 16); - - ecm += 12; - irdeto2_decrypt(ecm, keyIV, keySeed, length); - - i = (ecm[0] & 7) + 1; - end = length - 8 < 0 ? 0 : length - 8; - - while (i < end) - { - l = ecm[i + 1] ? (ecm[i + 1] & 0x3F) + 2 : 1; - - switch (ecm[i]) - { - case 0x10: - case 0x50: - if (l == 0x13 && i <= length - 8 - l) - { - irdeto2_decrypt(&ecm[i + 3], keyIV, key, 16); - } - break; - - case 0x78: - if (l == 0x14 && i <= length - 8 - l) - { - irdeto2_decrypt(&ecm[i + 4], keyIV, key, 16); - } - break; - } - i += l; - } - - i = (ecm[0] & 7) + 1; - - if (calculate_hash(keySeed, keyIV, ecm - 6, length + 6)) - { - while (i < end) - { - l = ecm[i + 1] ? (ecm[i + 1] & 0x3F) + 2 : 1; - - switch (ecm[i]) - { - case 0x78: - { - if (l == 0x14 && i <= length - 8 - l) - { - memcpy(dw, &ecm[i + 4], 16); - - for (j = 0; j < 16; j += 4) // fix dw checksum bytes - { - dw[j + 3] = (dw[j] + dw[j + 1] + dw[j + 2]) & 0xFF; - } - return EMU_OK; - } - } - } - i += l; - } - } - } - - if (keyIVRef == 0) - { - return EMU_KEY_NOT_FOUND; - } - } - - if (keySeedRef == 0) - { - return EMU_KEY_NOT_FOUND; - } - } - - if (key0Ref == 0) - { - return EMU_KEY_NOT_FOUND; - } - - return EMU_NOT_SUPPORTED; -} - -// Irdeto2 EMM EMU -static int8_t do_emm_type_op(uint32_t ident, uint8_t *emm, uint8_t *keySeed, uint8_t *keyIV, uint8_t *keyPMK, - uint16_t emmLen, uint8_t startOffset, uint8_t length, uint32_t *keysAdded) -{ - uint8_t tmp[16]; - uint32_t end, i, l; - char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[36]; - - memset(tmp, 0, 16); - irdeto2_encrypt(keySeed, tmp, keyPMK, 16); - irdeto2_decrypt(&emm[startOffset], keyIV, keySeed, length); - - i = 16; - end = startOffset + (length - 8 < 0 ? 0 : length - 8); - - while (i < end) - { - l = emm[i + 1] ? (emm[i + 1] & 0x3F) + 2 : 1; - - switch (emm[i]) - { - case 0x10: - case 0x50: - if (l == 0x13 && i <= startOffset + length - 8 - l) - { - irdeto2_decrypt(&emm[i + 3], keyIV, keyPMK, 16); - } - break; - - case 0x78: - if (l == 0x14 && i <= startOffset + length - 8 - l) - { - irdeto2_decrypt(&emm[i + 4], keyIV, keyPMK, 16); - } - break; - } - i += l; - } - - memmove(emm + 6, emm + 7, emmLen - 7); - - i = 15; - end = startOffset + (length - 9 < 0 ? 0 : length - 9); - - if (calculate_hash(keySeed, keyIV, emm + 3, emmLen - 4)) - { - while (i < end) - { - l = emm[i + 1] ? (emm[i + 1] & 0x3F) + 2 : 1; - - switch (emm[i]) - { - case 0x10: - case 0x50: - { - if (l == 0x13 && i <= startOffset + length - 9 - l) - { - snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%02X", emm[i + 2] >> 2); - SAFE_MUTEX_LOCK(&emu_key_data_mutex); - emu_set_key('I', ident, keyName, &emm[i + 3], 16, 1, NULL, NULL); - SAFE_MUTEX_UNLOCK(&emu_key_data_mutex); - - (*keysAdded)++; - cs_hexdump(0, &emm[i + 3], 16, keyValue, sizeof(keyValue)); - cs_log("Key found in EMM: I %06X %s %s", ident, keyName, keyValue); - } - } - } - i += l; - } - - if (*keysAdded > 0) - { - return 0; - } - } - - return 1; -} - -static int8_t do_emm_type_pmk(uint32_t ident, uint8_t *emm, uint8_t *keySeed, uint8_t *keyIV, uint8_t *keyPMK, - uint16_t emmLen, uint8_t startOffset, uint8_t length, uint32_t *keysAdded) -{ - uint32_t end, i, j, l; - char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[36]; - - irdeto2_decrypt(&emm[startOffset], keyIV, keySeed, length); - - i = 13; - end = startOffset + (length - 8 < 0 ? 0 : length - 8); - - while (i < end) - { - l = emm[i + 1] ? (emm[i + 1] & 0x3F) + 2 : 1; - - switch (emm[i]) - { - case 0x10: - case 0x50: - if (l == 0x13 && i <= startOffset + length - 8 - l) - { - irdeto2_decrypt(&emm[i + 3], keyIV, keyPMK, 16); - } - break; - - case 0x78: - if (l == 0x14 && i <= startOffset + length - 8 - l) - { - irdeto2_decrypt(&emm[i + 4], keyIV, keyPMK, 16); - } - break; - - case 0x68: - if (l == 0x26 && i <= startOffset + length - 8 - l) - { - irdeto2_decrypt(&emm[i + 3], keyIV, keyPMK, 16 * 2); - } - break; - } - i += l; - } - - memmove(emm + 7, emm + 9, emmLen - 9); - - i = 11; - end = startOffset + (length - 10 < 0 ? 0 : length - 10); - - if (calculate_hash(keySeed, keyIV, emm + 3, emmLen - 5)) - { - while (i < end) - { - l = emm[i + 1] ? (emm[i + 1] & 0x3F) + 2 : 1; - - switch (emm[i]) - { - case 0x68: - { - if (l == 0x26 && i <= startOffset + length - 10 - l) - { - for (j = 0; j < 2; j++) - { - snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "M%01X", 3 + j); - SAFE_MUTEX_LOCK(&emu_key_data_mutex); - emu_set_key('I', ident, keyName, &emm[i + 3 + j * 16], 16, 1, NULL, NULL); - SAFE_MUTEX_UNLOCK(&emu_key_data_mutex); - - (*keysAdded)++; - cs_hexdump(0, &emm[i + 3 + j * 16], 16, keyValue, sizeof(keyValue)); - cs_log("Key found in EMM: I %06X %s %s", ident, keyName, keyValue); - } - } - } - } - i += l; - } - - if (*keysAdded > 0) - { - return 0; - } - } - - return 1; -} - -static const uint8_t fausto_xor[16] = -{ - 0x22, 0x58, 0xBD, 0x85, 0x2E, 0x8E, 0x52, 0x80, - 0xA3, 0x79, 0x98, 0x69, 0x68, 0xE2, 0xD8, 0x4D -}; - -int8_t irdeto2_emm(uint16_t caid, uint8_t *oemm, uint32_t *keysAdded) -{ - uint8_t length, okeySeed[16], keySeed[16], keyIV[16], keyPMK[16], startOffset, emmType; - uint8_t emmCopy[EMU_MAX_EMM_LEN], *emm = oemm; - uint16_t emmLen = SCT_LEN(emm); - uint32_t ident, keySeedRef, keyIVRef, keyPMK0Ref, keyPMK1Ref, keyPMK0ERef, keyPMK1ERef; - - if (emmLen < 11) - { - return EMU_NOT_SUPPORTED; - } - - if (emm[3] == 0xC3 || emm[3] == 0xCB) - { - emmType = 2; - startOffset = 11; - } - else - { - emmType = 1; - startOffset = 10; - } - - ident = emm[startOffset - 2] | caid << 8; - length = emm[startOffset - 1]; - - if (emmLen < length + startOffset) - { - return EMU_NOT_SUPPORTED; - } - - keySeedRef = 0; - - while (get_key(okeySeed, ident, 'M', emmType == 1 ? 0 : 0xA, 1, &keySeedRef)) - { - keyIVRef = 0; - - while (get_key(keyIV, ident, 'M', 2, 1, &keyIVRef)) - { - keyPMK0Ref = 0; - keyPMK1Ref = 0; - keyPMK0ERef = 0; - keyPMK1ERef = 0; - - while (get_key(keyPMK, ident, 'M', emmType == 1 ? 3 : 0xB, 1, &keyPMK0Ref)) - { - memcpy(keySeed, okeySeed, 16); - memcpy(emmCopy, oemm, emmLen); - emm = emmCopy; - - if (emmType == 1) - { - if (do_emm_type_op(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) - { - return EMU_OK; - } - } - else - { - if (do_emm_type_pmk(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) - { - return EMU_OK; - } - } - } - - if (emmType == 1) - { - while (get_key(keyPMK, ident, 'M', 4, 1, &keyPMK1Ref)) - { - memcpy(keySeed, okeySeed, 16); - memcpy(emmCopy, oemm, emmLen); - emm = emmCopy; - - if (do_emm_type_op(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) - { - return EMU_OK; - } - } - - while (get_key(keyPMK, ident, 'M', 5, 1, &keyPMK0ERef)) - { - xxor(keyPMK, 16, keyPMK, fausto_xor); - memcpy(keySeed, okeySeed, 16); - memcpy(emmCopy, oemm, emmLen); - emm = emmCopy; - - if (do_emm_type_op(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) - { - return EMU_OK; - } - } - - while (get_key(keyPMK, ident, 'M', 6, 1, &keyPMK1ERef)) - { - xxor(keyPMK, 16, keyPMK, fausto_xor); - memcpy(keySeed, okeySeed, 16); - memcpy(emmCopy, oemm, emmLen); - emm = emmCopy; - - if (do_emm_type_op(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) - { - return EMU_OK; - } - } - } - - if (keyPMK0Ref == 0 && keyPMK1Ref == 0 && keyPMK0ERef == 0 && keyPMK1ERef == 0) - { - return EMU_KEY_NOT_FOUND; - } - } - - if (keyIVRef == 0) - { - return EMU_KEY_NOT_FOUND; - } - } - - if (keySeedRef == 0) - { - return 2; - } - - return EMU_NOT_SUPPORTED; -} - -int8_t irdeto2_get_hexserial(uint16_t caid, uint8_t *hexserial) -{ - uint32_t i, len; - KeyDataContainer *KeyDB; - KeyData *tmpKeyData; - - KeyDB = emu_get_key_container('I'); - - if (KeyDB == NULL) - { - return 0; - } - - for (i = 0; i < KeyDB->keyCount; i++) - { - if (KeyDB->EmuKeys[i].provider >> 8 != caid) - { - continue; - } - - if (strcmp(KeyDB->EmuKeys[i].keyName, "MC")) - { - continue; - } - - tmpKeyData = &KeyDB->EmuKeys[i]; - len = tmpKeyData->keyLength; - - if (len > 3) - { len = 3; } - - memcpy(hexserial + (3 - len), tmpKeyData->key, len); - return 1; - } - - return 0; -} - -#endif // WITH_EMU diff --git a/module-emulator-irdeto.h b/module-emulator-irdeto.h deleted file mode 100755 index e13af0a..0000000 --- a/module-emulator-irdeto.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef MODULE_EMULATOR_IRDETO_H -#define MODULE_EMULATOR_IRDETO_H - -#ifdef WITH_EMU - -int8_t irdeto2_ecm(uint16_t caid, uint8_t *oecm, uint8_t *dw); -int8_t irdeto2_emm(uint16_t caid, uint8_t *oemm, uint32_t *keysAdded); - -// hexserial must be of type "uint8_t hexserial[3]" -// returns 0 on error, 1 on success -int8_t irdeto2_get_hexserial(uint16_t caid, uint8_t *hexserial); - -#endif // WITH_EMU - -#endif // MODULE_EMULATOR_IRDETO_H diff --git a/module-emulator-nagravision.c b/module-emulator-nagravision.c deleted file mode 100755 index a097871..0000000 --- a/module-emulator-nagravision.c +++ /dev/null @@ -1,376 +0,0 @@ -#define MODULE_LOG_PREFIX "emu" - -#include "globals.h" - -#ifdef WITH_EMU - -#include "cscrypt/bn.h" -#include "cscrypt/des.h" -#include "cscrypt/idea.h" -#include "module-emulator-osemu.h" - -static void reverse_mem(uint8_t *in, int32_t len) -{ - uint8_t temp; - int32_t i; - - for (i = 0; i < (len / 2); i++) - { - temp = in[i]; - in[i] = in[len - i - 1]; - in[len - i - 1] = temp; - } -} - -static void reverse_mem_in_out(uint8_t *out, const uint8_t *in, int32_t n) -{ - if (n > 0) - { - out += n; - do - { - *(--out) = *(in++); - } - while (--n); - } -} - -static int8_t rsa_input(BIGNUM *d, const uint8_t *in, int32_t n, int8_t le) -{ - int8_t result = 0; - - if (le) - { - uint8_t *tmp = (uint8_t *)malloc(sizeof(uint8_t) * n); - - if (tmp == NULL) - { - return 0; - } - - reverse_mem_in_out(tmp, in, n); - result = BN_bin2bn(tmp, n, d) != 0; - free(tmp); - } - else - { - result = BN_bin2bn(in, n, d) != 0; - } - - return result; -} - -static int32_t rsa_output(uint8_t *out, int32_t n, BIGNUM *r, int8_t le) -{ - int32_t s = BN_num_bytes(r); - - if (s > n) - { - uint8_t *buff = (uint8_t *)malloc(sizeof(uint8_t) * s); - - if (buff == NULL) - { - return 0; - } - - BN_bn2bin(r, buff); - memcpy(out, buff + s - n, n); - free(buff); - } - else if (s < n) - { - int32_t l = n - s; - - memset(out, 0, l); - BN_bn2bin(r, out + l); - } - else - { - BN_bn2bin(r, out); - } - - if (le) - { - reverse_mem(out, n); - } - - return s; -} - -static int32_t emu_rsa(uint8_t *out, const uint8_t *in, int32_t n, BIGNUM *exp, BIGNUM *mod, int8_t le) -{ - BN_CTX *ctx; - BIGNUM *r, *d; - int32_t result = 0; - - ctx = BN_CTX_new(); - r = BN_new(); - d = BN_new(); - - if (rsa_input(d, in, n, le) && BN_mod_exp(r, d, exp, mod, ctx)) - { - result = rsa_output(out, n, r, le); - } - - BN_free(d); - BN_free(r); - BN_CTX_free(ctx); - - return result; -} - -// Nagra EMU - -static int8_t get_key(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint8_t isCriticalKey) -{ - char keyStr[EMU_MAX_CHAR_KEYNAME]; - snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); - - if (emu_find_key('N', ident, 0, keyStr, buf, keyName == 'M' ? 64 : 16, isCriticalKey, 0, 0, NULL)) - { - return 1; - } - - return 0; -} - -static int8_t nagra2_signature(const uint8_t *vkey, const uint8_t *sig, const uint8_t *msg, int32_t len) -{ - uint8_t buff[16], iv[8]; - int32_t i, j; - - memcpy(buff, vkey, sizeof(buff)); - - for (i = 0; i + 7 < len; i += 8) - { - IDEA_KEY_SCHEDULE ek; - - idea_set_encrypt_key(buff, &ek); - memcpy(buff, buff + 8, 8); - memset(iv, 0, sizeof(iv)); - idea_cbc_encrypt(msg + i, buff + 8, 8, &ek, iv, IDEA_ENCRYPT); - - for (j = 7; j >= 0; j--) - { - buff[j + 8] ^= msg[i + j]; - } - } - - buff[8] &= 0x7F; - - return (memcmp(sig, buff + 8, 8) == 0); -} - -static int8_t decrypt_ecm(uint8_t *in, uint8_t *out, const uint8_t *key, int32_t len, - const uint8_t *vkey, uint8_t *keyM) -{ - BIGNUM *exp, *mod; - uint8_t iv[8]; - int32_t i = 0, sign = in[0] & 0x80; - uint8_t binExp = 3; - int8_t result = 1; - - exp = BN_new(); - mod = BN_new(); - BN_bin2bn(&binExp, 1, exp); - BN_bin2bn(keyM, 64, mod); - - if (emu_rsa(out, in + 1, 64, exp, mod, 1) <= 0) - { - BN_free(exp); - BN_free(mod); - return 0; - } - - out[63] |= sign; - - if (len > 64) - { - memcpy(out + 64, in + 65, len - 64); - } - - memset(iv, 0, sizeof(iv)); - - if (in[0] & 0x04) - { - uint8_t key1[8], key2[8]; - - reverse_mem_in_out(key1, &key[0], 8); - reverse_mem_in_out(key2, &key[8], 8); - - for (i = 7; i >= 0; i--) - { - reverse_mem(out + 8 * i, 8); - } - - des_ede2_cbc_decrypt(out, iv, key1, key2, len); - - for (i = 7; i >= 0; i--) - { - reverse_mem(out + 8 * i, 8); - } - } - else - { - IDEA_KEY_SCHEDULE ek; - - idea_set_encrypt_key(key, &ek); - idea_cbc_encrypt(out, out, len & ~7, &ek, iv, IDEA_DECRYPT); - } - - reverse_mem(out, 64); - - if (result && emu_rsa(out, out, 64, exp, mod, 0) <= 0) - { - result = 0; - } - - if (result && vkey && !nagra2_signature(vkey, out, out + 8, len - 8)) - { - result = 0; - } - - BN_free(exp); - BN_free(mod); - return result; -} - -int8_t nagra2_ecm(uint8_t *ecm, uint8_t *dw) -{ - int8_t useVerifyKey = 0; - int32_t l = 0, s; - - uint8_t cmdLen, ideaKeyNr, *dec, ideaKey[16], vKey[16], m1Key[64], mecmAlgo = 0; - uint16_t i = 0, ecmLen = SCT_LEN(ecm); - uint32_t ident, identMask, tmp1, tmp2, tmp3; - - if (ecmLen < 8) - { - return EMU_NOT_SUPPORTED; - } - - cmdLen = ecm[4] - 5; - ident = (ecm[5] << 8) + ecm[6]; - ideaKeyNr = (ecm[7] & 0x10) >> 4; - - if (ideaKeyNr) - { - ideaKeyNr = 1; - } - - if (ident == 1283 || ident == 1285 || ident == 1297) - { - ident = 1281; - } - - if (cmdLen <= 63 || ecmLen < cmdLen + 10) - { - return EMU_NOT_SUPPORTED; - } - - if (!get_key(ideaKey, ident, '0', ideaKeyNr, 1)) - { - return EMU_KEY_NOT_FOUND; - } - - if (get_key(vKey, ident, 'V', 0, 0)) - { - useVerifyKey = 1; - } - - if (!get_key(m1Key, ident, 'M', 1, 1)) - { - return EMU_KEY_NOT_FOUND; - } - - reverse_mem(m1Key, 64); - - dec = (uint8_t *)malloc(sizeof(uint8_t) * cmdLen); - if (dec == NULL) - { - return EMU_OUT_OF_MEMORY; - } - - if (!decrypt_ecm(ecm + 9, dec, ideaKey, cmdLen, useVerifyKey ? vKey : 0, m1Key)) - { - free(dec); - return EMU_NOT_SUPPORTED; - } - - for (i = (dec[14] & 0x10) ? 16 : 20; i < cmdLen && l != 3; ) - { - switch (dec[i]) - { - case 0x10: - case 0x11: - if (i + 10 < cmdLen && dec[i + 1] == 0x09) - { - s = (~dec[i]) & 1; - mecmAlgo = dec[i + 2] & 0x60; - memcpy(dw + (s << 3), &dec[i + 3], 8); - i += 11; - l |= (s + 1); - } - else - { - i++; - } - break; - - case 0x00: - i += 2; - break; - - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0xB0: - if (i + 1 < cmdLen) - { - i += dec[i + 1] + 2; - } - else - { - i++; - } - break; - - default: - i++; - continue; - } - } - - free(dec); - - if (l != 3) - { - return EMU_NOT_SUPPORTED; - } - - if (mecmAlgo > 0) - { - return EMU_NOT_SUPPORTED; - } - - identMask = ident & 0xFF00; - - if (identMask == 0x1100 || identMask == 0x500 || identMask == 0x3100) - { - memcpy(&tmp1, dw, 4); - memcpy(&tmp2, dw + 4, 4); - memcpy(&tmp3, dw + 12, 4); - memcpy(dw, dw + 8, 4); - memcpy(dw + 4, &tmp3, 4); - memcpy(dw + 8, &tmp1, 4); - memcpy(dw + 12, &tmp2, 4); - } - - return EMU_OK; -} - -#endif // WITH_EMU diff --git a/module-emulator-nagravision.h b/module-emulator-nagravision.h deleted file mode 100755 index 31810eb..0000000 --- a/module-emulator-nagravision.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef MODULE_EMULATOR_NAGRAVISION_H -#define MODULE_EMULATOR_NAGRAVISION_H - -#ifdef WITH_EMU - -int8_t nagra2_ecm(uint8_t *ecm, uint8_t *dw); - -#endif // WITH_EMU - -#endif // MODULE_EMULATOR_NAGRAVISION_H diff --git a/module-emulator-omnicrypt.c b/module-emulator-omnicrypt.c deleted file mode 100755 index 805926d..0000000 --- a/module-emulator-omnicrypt.c +++ /dev/null @@ -1,72 +0,0 @@ -#define MODULE_LOG_PREFIX "emu" - -#include "globals.h" - -#ifdef WITH_EMU - -#include "module-emulator-osemu.h" -#include "module-emulator-omnicrypt.h" -#include "oscam-aes.h" -#include "oscam-string.h" - - -static inline int8_t get_ecm_key(uint16_t provider, uint8_t parity, uint8_t *key) -{ - return emu_find_key('O', provider, 0, parity == 0 ? "00" : "01", key, 16, 1, 0, 0, NULL); -} - -int8_t omnicrypt_ecm(uint8_t *ecm, uint8_t *dw) -{ - uint8_t section_syntax_indicator, session_key[16], session_key_parity, position; - uint16_t private_section_length, session_key_id, payload_length; - struct aes_keys aes; - - section_syntax_indicator = ecm[1] >> 7; - if (section_syntax_indicator != 0) // The private_data_bytes immediately follow the private_section_length field - { - cs_log("ECM section syntax indicator %d not supported", section_syntax_indicator); - return EMU_NOT_SUPPORTED; - } - - private_section_length = b2i(2, ecm + 1) & 0x0FFF; - if (private_section_length != 0x2D) - { - cs_log("ECM has an unsupported private section length of %d", private_section_length); - return EMU_NOT_SUPPORTED; - } - - session_key_parity = ecm[3] & 0x01; - session_key_id = b2i(2, ecm + 4); - - if (!get_ecm_key(session_key_id, session_key_parity, session_key)) - { - return EMU_KEY_NOT_FOUND; - } - aes_set_key(&aes, (char *)session_key); - - payload_length = b2i(2, ecm + 6) & 0x0FFF; - if (payload_length != 0x28) - { - cs_log("ECM has an unsupported payload length of %d", payload_length); - return EMU_NOT_SUPPORTED; - } - - for (position = 8; position + 1 < payload_length; position += 4 + 16) // Run twice for odd, even CW - { - uint8_t parity = ecm[position + 1] & 0x01; - uint8_t length = ecm[position + 3]; - - if (length != 16) - { - cs_log("CW %d has an unsupported length of %d", parity, length); - return EMU_NOT_SUPPORTED; - } - - aes_decrypt(&aes, ecm + position + 4, 16); - memcpy(dw + parity * 8, ecm + position + 4, 8); // Copy the first 8 bytes (rest are zeros) - } - - return EMU_OK; -} - -#endif // WITH_EMU diff --git a/module-emulator-omnicrypt.h b/module-emulator-omnicrypt.h deleted file mode 100755 index 3af8915..0000000 --- a/module-emulator-omnicrypt.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef MODULE_EMULATOR_OMNICRYPT_H -#define MODULE_EMULATOR_OMNICRYPT_H - -#ifdef WITH_EMU - -int8_t omnicrypt_ecm(uint8_t *ecm, uint8_t *dw); - -#endif // WITH_EMU - -#endif // MODULE_EMULATOR_OMNICRYPT_H diff --git a/module-emulator-osemu.c b/module-emulator-osemu.c deleted file mode 100755 index a3f8db3..0000000 --- a/module-emulator-osemu.c +++ /dev/null @@ -1,986 +0,0 @@ -#define MODULE_LOG_PREFIX "emu" - -#include "globals.h" - -#ifdef WITH_EMU - -#include "oscam-string.h" -#include "module-streamrelay.h" -#include "module-emulator-osemu.h" -#include "module-emulator-biss.h" -#include "module-emulator-cryptoworks.h" -#include "module-emulator-director.h" -#include "module-emulator-irdeto.h" -#include "module-emulator-nagravision.h" -#include "module-emulator-omnicrypt.h" -#include "module-emulator-powervu.h" -#include "module-emulator-viaccess.h" - -// Shared functions - -int8_t is_valid_dcw(uint8_t *dw) -{ - uint8_t i; - - for (i = 0; i < 8; i+= 4) - { - if (((dw[i] + dw[i + 1] + dw[i + 2]) & 0xFF) != dw[i + 3]) - { - return 0; - } - } - - return 1; -} - -int8_t char_to_bin(uint8_t *out, const char *in, uint32_t inLen) -{ - uint32_t i, tmp; - - for (i = 0; i < inLen / 2; i++) - { - if (sscanf(in + i * 2, "%02X", &tmp) != 1) - { - return 0; - } - out[i] = (uint8_t)tmp; - } - return 1; -} - -void date_to_str(char *dateStr, uint8_t len, int8_t offset, uint8_t format) -{ - // Creates a formatted date string for use in various functions. - // A positive or negative time offset (in hours) can be set as well - // as the format of the output string. - - time_t rawtime; - struct tm timeinfo; - - time(&rawtime); - rawtime += (time_t) offset * 60 * 60; // Add a positive or negative offset - localtime_r(&rawtime, &timeinfo); - - switch (format) - { - case 1: - strftime(dateStr, len, "%c", &timeinfo); - break; - - case 2: - strftime(dateStr, len, "%F @ %R", &timeinfo); - break; - - case 3: - strftime(dateStr, len, "%y%m%d%H", &timeinfo); - break; - } -} - -/* - * Key DB - * - * The Emu reader gets keys from the OSCcam-Emu binary and the "SoftCam.Key" file. - * - * The keys are stored in structures of type "KeyDataContainer", one per CAS. Each - * container points to a dynamically allocated array of type "KeyData", which holds - * the actual keys. The array initially holds up to 64 keys (64 * KeyData), and it - * is expanded by 16 every time it's filled with keys. The "KeyDataContainer" also - * includes info about the number of keys it contains ("KeyCount") and the maximum - * number of keys it can store ("KeyMax"). - * - * The "KeyData" structure, on the other hand, stores the actual key information, - * including the "identifier", "provider", "keyName", "key" and "keyLength". There - * is also a "nextKey" pointer to a similar "KeyData" structure which is only used - * for Irdeto multiple keys, in a linked list style structure. For all other CAS, - * the "nextKey" is a "NULL" pointer. - * - * For storing keys, the "SetKey" function is used. Duplicate keys are not allowed. - * When storing a key that is already present in the database, its "key" value is - * updated with the new one. For reading keys from the database, the "FindKey" - * function is used. To delete all keys in a container, the "DeleteKeysInContainer" - * function can be called. -*/ - -char *emu_keyfile_path = NULL; - -void emu_set_keyfile_path(const char *path) -{ - uint32_t pathLength; - - if (emu_keyfile_path != NULL) - { - free(emu_keyfile_path); - } - - pathLength = cs_strlen(path); - emu_keyfile_path = (char *)malloc(pathLength + 1); - if (emu_keyfile_path == NULL) - { - return; - } - cs_strncpy(emu_keyfile_path, path, pathLength + 1); -} - -KeyDataContainer CwKeys = { NULL, 0, 0 }; -KeyDataContainer ViKeys = { NULL, 0, 0 }; -KeyDataContainer NagraKeys = { NULL, 0, 0 }; -KeyDataContainer IrdetoKeys = { NULL, 0, 0 }; -KeyDataContainer BissSWs = { NULL, 0, 0 }; -KeyDataContainer Biss2Keys = { NULL, 0, 0 }; -KeyDataContainer OmnicryptKeys = { NULL, 0, 0 }; -KeyDataContainer PowervuKeys = { NULL, 0, 0 }; -KeyDataContainer TandbergKeys = { NULL, 0, 0 }; -KeyDataContainer StreamKeys = { NULL, 0, 0 }; - -KeyDataContainer *emu_get_key_container(char identifier) -{ - switch (identifier) - { - case 'W': - return &CwKeys; - case 'V': - return &ViKeys; - case 'N': - return &NagraKeys; - case 'I': - return &IrdetoKeys; - case 'F': - return &BissSWs; - case 'G': - return &Biss2Keys; - case 'O': - return &OmnicryptKeys; - case 'P': - return &PowervuKeys; - case 'T': - return &TandbergKeys; - case 'A': - return &StreamKeys; - default: - return NULL; - } -} - -static void write_key_to_file(char identifier, uint32_t provider, const char *keyName, uint8_t *key, - uint32_t keyLength, char *comment) -{ - char line[1200], dateText[100], filename[EMU_KEY_FILENAME_MAX_LEN + 1]; - char *path, *filepath, *keyValue; - uint32_t pathLength; - uint8_t fileNameLen = cs_strlen(EMU_KEY_FILENAME); - struct dirent *pDirent; - DIR *pDir; - FILE *file = NULL; - - pathLength = cs_strlen(emu_keyfile_path); - path = (char *)malloc(pathLength + 1); - if (path == NULL) - { - return; - } - cs_strncpy(path, emu_keyfile_path, pathLength + 1); - - pathLength = cs_strlen(path); - if (pathLength >= fileNameLen && strcasecmp(path + pathLength - fileNameLen, EMU_KEY_FILENAME) == 0) - { - // cut file name - path[pathLength - fileNameLen] = '\0'; - } - - pathLength = cs_strlen(path); - if (path[pathLength - 1] == '/' || path[pathLength - 1] == '\\') - { - // cut trailing / - path[pathLength - 1] = '\0'; - } - - pDir = opendir(path); - if (pDir == NULL) - { - cs_log("Cannot open key file path: %s", path); - free(path); - return; - } - - while ((pDirent = readdir(pDir)) != NULL) - { - if (strcasecmp(pDirent->d_name, EMU_KEY_FILENAME) == 0) - { - cs_strncpy(filename, pDirent->d_name, sizeof(filename)); - break; - } - } - closedir(pDir); - - if (pDirent == NULL) - { - cs_strncpy(filename, EMU_KEY_FILENAME, sizeof(filename)); - } - - pathLength = cs_strlen(path) + 1 + cs_strlen(filename) + 1; - filepath = (char *)malloc(pathLength); - if (filepath == NULL) - { - free(path); - return; - } - snprintf(filepath, pathLength, "%s/%s", path, filename); - free(path); - - cs_log("Writing key file: %s", filepath); - - file = fopen(filepath, "a"); - free(filepath); - if (file == NULL) - { - return; - } - - date_to_str(dateText, sizeof(dateText), 0, 1); - - keyValue = (char *)malloc((keyLength * 2) + 1); - if (keyValue == NULL) - { - fclose(file); - return; - } - cs_hexdump(0, key, keyLength, keyValue, (keyLength * 2) + 1); - - if (comment) - { - snprintf(line, sizeof(line), "\n%c %08X %s %s ; added by Emu %s %s", - identifier, provider, keyName, keyValue, dateText, comment); - } - else - { - snprintf(line, sizeof(line), "\n%c %08X %s %s ; added by Emu %s", - identifier, provider, keyName, keyValue, dateText); - } - - cs_log("Key written: %c %08X %s %s", identifier, provider, keyName, keyValue); - - free(keyValue); - - fwrite(line, cs_strlen(line), 1, file); - fclose(file); -} - -int8_t emu_set_key(char identifier, uint32_t provider, char *keyName, uint8_t *orgKey, uint32_t keyLength, - uint8_t writeKey, char *comment, struct s_reader *rdr) -{ - uint32_t i, j; - uint8_t *tmpKey = NULL; - KeyDataContainer *KeyDB; - KeyData *tmpKeyData, *newKeyData; - - identifier = (char)toupper((int)identifier); - - KeyDB = emu_get_key_container(identifier); - if (KeyDB == NULL) - { - return 0; - } - - keyName = strtoupper(keyName); - - if (identifier == 'F') // Prepare BISS keys before saving to the db - { - // Convert legacy BISS "00" & "01" keynames - if (0 == strcmp(keyName, "00") || 0 == strcmp(keyName, "01")) - { - keyName = "00000000"; - } - - // All keyNames should have a length of 8 after converting - if (cs_strlen(keyName) != 8) - { - cs_log("WARNING: Wrong key format in %s: F %08X %s", EMU_KEY_FILENAME, provider, keyName); - return 0; - } - - // Verify date-coded keyName (if enabled), ignoring old (expired) keys - if (rdr->emu_datecodedenabled) - { - char timeStr[9]; - date_to_str(timeStr, sizeof(timeStr), 0, 3); - - // Reject old date-coded keys, but allow our "00000000" evergreen label - if (strcmp("00000000", keyName) != 0 && strcmp(timeStr, keyName) >= 0) - { - return 0; - } - } - } - - // Fix checksum for BISS keys with a length of 6 - if (identifier == 'F' && keyLength == 6) - { - tmpKey = (uint8_t *)malloc(8 * sizeof(uint8_t)); - if(tmpKey == NULL) - { - return 0; - } - - tmpKey[0] = orgKey[0]; - tmpKey[1] = orgKey[1]; - tmpKey[2] = orgKey[2]; - tmpKey[3] = ((orgKey[0] + orgKey[1] + orgKey[2]) & 0xFF); - tmpKey[4] = orgKey[3]; - tmpKey[5] = orgKey[4]; - tmpKey[6] = orgKey[5]; - tmpKey[7] = ((orgKey[3] + orgKey[4] + orgKey[5]) & 0xFF); - - keyLength = 8; - } - else // All keys with a length of 8, including BISS - { - tmpKey = (uint8_t *)malloc(keyLength * sizeof(uint8_t)); - if (tmpKey == NULL) - { - return 0; - } - - memcpy(tmpKey, orgKey, keyLength); - } - - // Fix patched mgcamd format for Irdeto - if (identifier == 'I' && provider < 0xFFFF) - { - provider = provider << 8; - } - - // Key already exists on db, update its value - for (i = 0; i < KeyDB->keyCount; i++) - { - if (KeyDB->EmuKeys[i].provider != provider) - { - continue; - } - - // Don't match keyName (i.e. expiration date) for BISS1 and BISS2 mode 1/E sesssion words - if (identifier != 'F' && strcmp(KeyDB->EmuKeys[i].keyName, keyName)) - { - continue; - } - - // Allow multiple keys for Irdeto - if (identifier == 'I') - { - // Reject duplicates - tmpKeyData = &KeyDB->EmuKeys[i]; - do - { - if (memcmp(tmpKeyData->key, tmpKey, tmpKeyData->keyLength < keyLength ? tmpKeyData->keyLength : keyLength) == 0) - { - free(tmpKey); - return 0; - } - tmpKeyData = tmpKeyData->nextKey; - } - while(tmpKeyData != NULL); - - // Add new key - newKeyData = (KeyData *)malloc(sizeof(KeyData)); - if (newKeyData == NULL) - { - free(tmpKey); - return 0; - } - - newKeyData->identifier = identifier; - newKeyData->provider = provider; - - if (cs_strlen(keyName) < EMU_MAX_CHAR_KEYNAME) - { - cs_strncpy(newKeyData->keyName, keyName, EMU_MAX_CHAR_KEYNAME); - } - else - { - memcpy(newKeyData->keyName, keyName, EMU_MAX_CHAR_KEYNAME); - } - - newKeyData->keyName[EMU_MAX_CHAR_KEYNAME - 1] = 0; - newKeyData->key = tmpKey; - newKeyData->keyLength = keyLength; - newKeyData->nextKey = NULL; - - tmpKeyData = &KeyDB->EmuKeys[i]; - j = 0; - - while (tmpKeyData->nextKey != NULL) - { - if (j == 0xFE) - { - break; - } - tmpKeyData = tmpKeyData->nextKey; - j++; - } - - if (tmpKeyData->nextKey) - { - NULLFREE(tmpKeyData->nextKey->key); - NULLFREE(tmpKeyData->nextKey); - } - tmpKeyData->nextKey = newKeyData; - - if (writeKey) - { - write_key_to_file(identifier, provider, keyName, tmpKey, keyLength, comment); - } - } - else // identifier != 'I' - { - free(KeyDB->EmuKeys[i].key); - KeyDB->EmuKeys[i].key = tmpKey; - KeyDB->EmuKeys[i].keyLength = keyLength; - - if (identifier == 'F') // Update keyName (i.e. expiration date) for BISS - { - cs_strncpy(KeyDB->EmuKeys[i].keyName, keyName, EMU_MAX_CHAR_KEYNAME); - } - - if (writeKey) - { - write_key_to_file(identifier, provider, keyName, tmpKey, keyLength, comment); - } - } - return 1; - } - - // Key does not exist on db - if (KeyDB->keyCount + 1 > KeyDB->keyMax) - { - if (KeyDB->EmuKeys == NULL) // db is empty - { - KeyDB->EmuKeys = (KeyData *)malloc(sizeof(KeyData) * (KeyDB->keyMax + 64)); - if (KeyDB->EmuKeys == NULL) - { - free(tmpKey); - return 0; - } - KeyDB->keyMax += 64; - } - else // db is full, expand it - { - tmpKeyData = (KeyData *)realloc(KeyDB->EmuKeys, sizeof(KeyData) * (KeyDB->keyMax + 16)); - if (tmpKeyData == NULL) - { - free(tmpKey); - return 0; - } - KeyDB->EmuKeys = tmpKeyData; - KeyDB->keyMax += 16; - } - } - - KeyDB->EmuKeys[KeyDB->keyCount].identifier = identifier; - KeyDB->EmuKeys[KeyDB->keyCount].provider = provider; - - if (cs_strlen(keyName) < EMU_MAX_CHAR_KEYNAME) - { - cs_strncpy(KeyDB->EmuKeys[KeyDB->keyCount].keyName, keyName, EMU_MAX_CHAR_KEYNAME); - } - else - { - memcpy(KeyDB->EmuKeys[KeyDB->keyCount].keyName, keyName, EMU_MAX_CHAR_KEYNAME); - } - - KeyDB->EmuKeys[KeyDB->keyCount].keyName[EMU_MAX_CHAR_KEYNAME - 1] = 0; - KeyDB->EmuKeys[KeyDB->keyCount].key = tmpKey; - KeyDB->EmuKeys[KeyDB->keyCount].keyLength = keyLength; - KeyDB->EmuKeys[KeyDB->keyCount].nextKey = NULL; - KeyDB->keyCount++; - - if (writeKey) - { - write_key_to_file(identifier, provider, keyName, tmpKey, keyLength, comment); - } - return 1; -} - -int8_t emu_find_key(char identifier, uint32_t provider, uint32_t providerIgnoreMask, char *keyName, - uint8_t *key, uint32_t maxKeyLength, uint8_t isCriticalKey, uint32_t keyRef, - uint8_t matchLength, uint32_t *getProvider) -{ - uint32_t i; - uint16_t j; - uint8_t provider_matching_key_count = 0; - KeyDataContainer *KeyDB; - KeyData *tmpKeyData; - - KeyDB = emu_get_key_container(identifier); - if (KeyDB == NULL) - { - return 0; - } - - for (i = 0; i < KeyDB->keyCount; i++) - { - if ((KeyDB->EmuKeys[i].provider & ~providerIgnoreMask) != provider) - { - continue; - } - - // Don't match keyName (i.e. expiration date) for BISS - if (identifier != 'F' && strcmp(KeyDB->EmuKeys[i].keyName, keyName)) - { - continue; - } - - // "matchLength" cannot be used when multiple keys are allowed - // for a single provider/keyName combination. - // Currently this is the case only for Irdeto keys. - if (matchLength && KeyDB->EmuKeys[i].keyLength != maxKeyLength) - { - continue; - } - - if (providerIgnoreMask) - { - if (provider_matching_key_count < keyRef) - { - provider_matching_key_count++; - continue; - } - else - { - keyRef = 0; - } - } - - tmpKeyData = &KeyDB->EmuKeys[i]; - - j = 0; - while (j < keyRef && tmpKeyData->nextKey != NULL) - { - j++; - tmpKeyData = tmpKeyData->nextKey; - } - - if (j == keyRef) - { - memcpy(key, tmpKeyData->key, tmpKeyData->keyLength > maxKeyLength ? maxKeyLength : tmpKeyData->keyLength); - if (tmpKeyData->keyLength < maxKeyLength) - { - memset(key + tmpKeyData->keyLength, 0, maxKeyLength - tmpKeyData->keyLength); - } - - // Report the keyName (i.e. expiration date) of the session word found - if (identifier == 'F') - { - cs_strncpy(keyName, tmpKeyData->keyName, EMU_MAX_CHAR_KEYNAME); - } - - if (getProvider != NULL) - { - (*getProvider) = tmpKeyData->provider; - } - return 1; - } - else - { - break; - } - } - - if (isCriticalKey) - { - cs_log("Key not found: %c %X %s", identifier, provider, keyName); - } - - return 0; -} - -int8_t emu_update_key(char identifier, uint32_t provider, char *keyName, uint8_t *key, - uint32_t keyLength, uint8_t writeKey, char *comment) -{ - uint32_t keyRef = 0; - uint8_t *tmpKey = (uint8_t *)malloc(sizeof(uint8_t) * keyLength); - - if (tmpKey == NULL) - { - return 0; - } - - while (emu_find_key(identifier, provider, 0, keyName, tmpKey, keyLength, 0, keyRef, 0, NULL)) - { - if (memcmp(tmpKey, key, keyLength) == 0) - { - free(tmpKey); - return 0; - } - - keyRef++; - } - - free(tmpKey); - return emu_set_key(identifier, provider, keyName, key, keyLength, writeKey, comment, NULL); -} - -static int32_t delete_keys_in_container(char identifier) -{ - // Deletes all keys stored in memory for the specified identifier, - // but keeps the container itself, re-initialized at { NULL, 0, 0 }. - // Returns the count of deleted keys. - - uint32_t oldKeyCount, i; - KeyData *tmpKeyData; - KeyDataContainer *KeyDB = emu_get_key_container(identifier); - - if (KeyDB == NULL || KeyDB->EmuKeys == NULL || KeyDB->keyCount == 0) - { - return 0; - } - - for (i = 0; i < KeyDB->keyCount; i++) - { - // For Irdeto multiple keys only (linked list structure) - while (KeyDB->EmuKeys[i].nextKey != NULL) - { - tmpKeyData = KeyDB->EmuKeys[i].nextKey; - KeyDB->EmuKeys[i].nextKey = KeyDB->EmuKeys[i].nextKey->nextKey; - free(tmpKeyData->key); // Free key - free(tmpKeyData); // Free KeyData - } - - // For single keys (all identifiers, including Irdeto) - free(KeyDB->EmuKeys[i].key); // Free key - } - - // Free the KeyData array - NULLFREE(KeyDB->EmuKeys); - oldKeyCount = KeyDB->keyCount; - KeyDB->keyCount = 0; - KeyDB->keyMax = 0; - - return oldKeyCount; -} - -void emu_clear_keydata(void) -{ - uint32_t total = 0; - - total = CwKeys.keyCount; - total += ViKeys.keyCount; - total += NagraKeys.keyCount; - total += IrdetoKeys.keyCount; - total += BissSWs.keyCount; - total += Biss2Keys.keyCount; - total += OmnicryptKeys.keyCount; - total += PowervuKeys.keyCount; - total += TandbergKeys.keyCount; - total += StreamKeys.keyCount; - - if (total != 0) - { - cs_log("Freeing keys in memory: W:%d V:%d N:%d I:%d F:%d G:%d O:%d P:%d T:%d A:%d", - CwKeys.keyCount, ViKeys.keyCount, NagraKeys.keyCount, IrdetoKeys.keyCount, BissSWs.keyCount, - Biss2Keys.keyCount, OmnicryptKeys.keyCount, PowervuKeys.keyCount, TandbergKeys.keyCount, - StreamKeys.keyCount); - - delete_keys_in_container('W'); - delete_keys_in_container('V'); - delete_keys_in_container('N'); - delete_keys_in_container('I'); - delete_keys_in_container('F'); - delete_keys_in_container('G'); - delete_keys_in_container('O'); - delete_keys_in_container('P'); - delete_keys_in_container('T'); - delete_keys_in_container('A'); - } -} - -uint8_t emu_read_keyfile(struct s_reader *rdr, const char *opath) -{ - char line[1200], keyName[EMU_MAX_CHAR_KEYNAME], keyString[1026], identifier; - char *path, *filepath, filename[EMU_KEY_FILENAME_MAX_LEN + 1]; - uint32_t pathLength, provider, keyLength; - uint8_t fileNameLen = cs_strlen(EMU_KEY_FILENAME); - uint8_t *key; - struct dirent *pDirent; - DIR *pDir; - FILE *file = NULL; - - pathLength = cs_strlen(opath); - path = (char *)malloc(pathLength + 1); - if (path == NULL) - { - return 0; - } - cs_strncpy(path, opath, pathLength + 1); - - pathLength = cs_strlen(path); - if (pathLength >= fileNameLen && strcasecmp(path + pathLength - fileNameLen, EMU_KEY_FILENAME) == 0) - { - // cut file name - path[pathLength - fileNameLen] = '\0'; - } - - pathLength = cs_strlen(path); - if (path[pathLength - 1] == '/' || path[pathLength - 1] == '\\') - { - // cut trailing / - path[pathLength - 1] = '\0'; - } - - pDir = opendir(path); - if (pDir == NULL) - { - cs_log("Cannot open key file path: %s", path); - free(path); - return 0; - } - - while ((pDirent = readdir(pDir)) != NULL) - { - if (strcasecmp(pDirent->d_name, EMU_KEY_FILENAME) == 0) - { - cs_strncpy(filename, pDirent->d_name, sizeof(filename)); - break; - } - } - closedir(pDir); - - if (pDirent == NULL) - { - cs_log("Key file not found in: %s", path); - free(path); - return 0; - } - - pathLength = cs_strlen(path) + 1 + cs_strlen(filename) + 1; - filepath = (char *)malloc(pathLength); - if (filepath == NULL) - { - free(path); - return 0; - } - snprintf(filepath, pathLength, "%s/%s", path, filename); - free(path); - - cs_log("Reading key file: %s", filepath); - - file = fopen(filepath, "r"); - free(filepath); - if (file == NULL) - { - return 0; - } - - emu_set_keyfile_path(opath); - - while (fgets(line, 1200, file)) - { - if (sscanf(line, "%c %8x %11s %1024s", &identifier, &provider, keyName, keyString) != 4) - { - continue; - } - - keyLength = cs_strlen(keyString) / 2; - key = (uint8_t *)malloc(keyLength); - if (key == NULL) - { - fclose(file); - return 0; - } - - if (char_to_bin(key, keyString, cs_strlen(keyString))) // Conversion OK - { - emu_set_key(identifier, provider, keyName, key, keyLength, 0, NULL, rdr); - } - else // Non-hex characters in keyString - { - if ((identifier != ';' && identifier != '#' && // Skip warning for comments, etc. - identifier != '=' && identifier != '-' && - identifier != ' ') && - !(identifier == 'F' && 0 == strncmp(keyString, "XXXXXXXXXXXX", 12))) // Skip warning for BISS 'Example key' lines - { - // Alert user regarding faulty line - cs_log("WARNING: non-hex value in %s at %c %08X %s %s", - EMU_KEY_FILENAME, identifier, provider, keyName, keyString); - } - } - free(key); - } - fclose(file); - - return 1; -} - -#if defined(WITH_SOFTCAM) && !defined(__APPLE__) && !defined(__ANDROID__) -extern uint8_t SoftCamKey_Data[] __asm__("_binary_SoftCam_Key_start"); -extern uint8_t SoftCamKey_DataEnd[] __asm__("_binary_SoftCam_Key_end"); - -void emu_read_keymemory(struct s_reader *rdr) -{ - char *keyData, *line, *saveptr, keyName[EMU_MAX_CHAR_KEYNAME], keyString[1026], identifier; - uint32_t provider, keyLength; - uint8_t *key; - - keyData = (char *)malloc(SoftCamKey_DataEnd - SoftCamKey_Data + 1); - if (keyData == NULL) - { - return; - } - memcpy(keyData, SoftCamKey_Data, SoftCamKey_DataEnd - SoftCamKey_Data); - keyData[SoftCamKey_DataEnd-SoftCamKey_Data] = 0x00; - - line = strtok_r(keyData, "\n", &saveptr); - while (line != NULL) - { - if (sscanf(line, "%c %8x %11s %1024s", &identifier, &provider, keyName, keyString) != 4) - { - line = strtok_r(NULL, "\n", &saveptr); - continue; - } - - keyLength = cs_strlen(keyString) / 2; - - key = (uint8_t *)malloc(keyLength); - if (key == NULL) - { - free(keyData); - return; - } - - if (char_to_bin(key, keyString, cs_strlen(keyString))) // Conversion OK - { - emu_set_key(identifier, provider, keyName, key, keyLength, 0, NULL, rdr); - } - else // Non-hex characters in keyString - { - if ((identifier != ';' && identifier != '#' && // Skip warning for comments, etc. - identifier != '=' && identifier != '-' && - identifier != ' ') && - !(identifier == 'F' && 0 == strncmp(keyString, "XXXXXXXXXXXX", 12))) // Skip warning for BISS 'Example key' lines - { - // Alert user regarding faulty line - cs_log("WARNING: non-hex value in internal keyfile at %c %08X %s %s", - identifier, provider, keyName, keyString); - } - } - free(key); - line = strtok_r(NULL, "\n", &saveptr); - } - free(keyData); -} -#else -void emu_read_keymemory(struct s_reader *UNUSED(rdr)) { } -#endif - -static const char *get_error_reason(int8_t result) -{ - switch (result) - { - case EMU_OK: - return "No error"; - - case EMU_NOT_SUPPORTED: - return "Not supported"; - - case EMU_KEY_NOT_FOUND: - return "Key not found"; - - case EMU_KEY_REJECTED: - return "ECM key rejected"; - - case EMU_CORRUPT_DATA: - return "Corrupt data"; - - case EMU_CW_NOT_FOUND: - return "CW not found"; - - case EMU_CHECKSUM_ERROR: - return "Checksum error"; - - case EMU_OUT_OF_MEMORY: - return "Out of memory"; - - default: - return "Unknown reason"; - } -} - -int8_t emu_process_ecm(struct s_reader *rdr, const ECM_REQUEST *er, uint8_t *cw, EXTENDED_CW *cw_ex) -{ - if (er->ecmlen < 3) - { - cs_log_dbg(D_TRACE, "Received ecm data of zero length!"); - return 4; - } - - uint16_t ecmLen = SCT_LEN(er->ecm); - uint8_t ecmCopy[ecmLen]; - int8_t result = 1; - - if (ecmLen != er->ecmlen) - { - cs_log_dbg(D_TRACE, "Actual ecm data length 0x%03X but ecm section length is 0x%03X", - er->ecmlen, ecmLen); - return 4; - } - - if (ecmLen > EMU_MAX_ECM_LEN) - { - cs_log_dbg(D_TRACE, "Actual ecm data length 0x%03X but maximum supported ecm length is 0x%03X", - er->ecmlen, EMU_MAX_ECM_LEN); - return 1; - } - - memcpy(ecmCopy, er->ecm, ecmLen); - - if (caid_is_viaccess(er->caid)) result = viaccess_ecm(ecmCopy, cw); - else if (caid_is_irdeto(er->caid)) result = irdeto2_ecm(er->caid, ecmCopy, cw); - else if (caid_is_cryptoworks(er->caid)) result = cryptoworks_ecm(er->caid, ecmCopy, cw); - else if (caid_is_powervu(er->caid)) - { -#ifdef MODULE_STREAMRELAY - result = powervu_ecm(ecmCopy, cw, cw_ex, er->srvid, er->caid, er->tsid, er->onid, er->ens, NULL); -#else - result = powervu_ecm(ecmCopy, cw, cw_ex, er->srvid, er->caid, er->tsid, er->onid, er->ens); -#endif - } - else if (caid_is_director(er->caid)) result = director_ecm(ecmCopy, cw); - else if (caid_is_nagra(er->caid)) result = nagra2_ecm(ecmCopy, cw); - else if (caid_is_biss(er->caid)) result = biss_ecm(rdr, er->ecm, er->caid, er->pid, cw, cw_ex); - else if (er->caid == 0x00FF) result = omnicrypt_ecm(ecmCopy, cw); // temp caid - - if (result != 0) - { - cs_log("ECM failed: %s", get_error_reason(result)); - } - - return result; -} - -int8_t emu_process_emm(struct s_reader *rdr, uint16_t caid, const uint8_t *emm, uint32_t *keysAdded) -{ - uint16_t emmLen = SCT_LEN(emm); - uint8_t emmCopy[emmLen]; - int8_t result = 1; - - if (emmLen > EMU_MAX_EMM_LEN) - { - return 1; - } - memcpy(emmCopy, emm, emmLen); - *keysAdded = 0; - - if (caid_is_viaccess(caid)) result = viaccess_emm(emmCopy, keysAdded); - else if (caid_is_irdeto(caid)) result = irdeto2_emm(caid, emmCopy, keysAdded); - else if (caid_is_powervu(caid)) result = powervu_emm(emmCopy, keysAdded); - else if (caid_is_director(caid)) result = director_emm(emmCopy, keysAdded); - else if (caid_is_biss_dynamic(caid)) result = biss_emm(rdr, emmCopy, keysAdded); - - if (result != 0) - { - cs_log_dbg(D_EMM,"EMM failed: %s", get_error_reason(result)); - } - - return result; -} - -#endif // WITH_EMU diff --git a/module-emulator-osemu.h b/module-emulator-osemu.h deleted file mode 100755 index a83dc64..0000000 --- a/module-emulator-osemu.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef MODULE_EMULATOR_OSEMU_H_ -#define MODULE_EMULATOR_OSEMU_H_ - -#ifdef WITH_EMU - -// Version info -#define EMU_VERSION 802 - -#define EMU_MAX_CHAR_KEYNAME 12 -#define EMU_KEY_FILENAME "SoftCam.Key" -#define EMU_KEY_FILENAME_MAX_LEN 31 -#define EMU_MAX_ECM_LEN MAX_ECM_SIZE -#define EMU_MAX_EMM_LEN MAX_EMM_SIZE - -/* - * Error codes for ProccessECM and ProccessEMM functions - * 0 - OK - * 1 - ECM / EMM not supported - * 2 - ECM / EMM key not found - * 3 - ECM key rejected - * 4 - Corrupt data - * 5 - CW not found - * 6 - CW / ECM / EMM checksum error - * 7 - Out of memory -*/ - -#define EMU_OK 0 -#define EMU_NOT_SUPPORTED 1 -#define EMU_KEY_NOT_FOUND 2 -#define EMU_KEY_REJECTED 3 -#define EMU_CORRUPT_DATA 4 -#define EMU_CW_NOT_FOUND 5 -#define EMU_CHECKSUM_ERROR 6 -#define EMU_OUT_OF_MEMORY 7 - -typedef struct KeyData KeyData; - -struct KeyData -{ - char identifier; - uint32_t provider; - char keyName[EMU_MAX_CHAR_KEYNAME]; - uint8_t *key; - uint32_t keyLength; - KeyData *nextKey; -}; - -typedef struct -{ - KeyData *EmuKeys; - uint32_t keyCount; - uint32_t keyMax; -} KeyDataContainer; - -extern KeyDataContainer CwKeys; -extern KeyDataContainer ViKeys; -extern KeyDataContainer NagraKeys; -extern KeyDataContainer IrdetoKeys; -extern KeyDataContainer BissSWs; // 'F' identifier - BISS1 and BISS2 mode 1/E session words -extern KeyDataContainer Biss2Keys; // 'G' identifier - BISS2 mode CA session keys (ECM keys) -extern KeyDataContainer OmnicryptKeys; -extern KeyDataContainer PowervuKeys; -extern KeyDataContainer TandbergKeys; -extern KeyDataContainer StreamKeys; -extern uint8_t viasat_const[]; -extern char *emu_keyfile_path; -extern pthread_mutex_t emu_key_data_mutex; - -void emu_set_keyfile_path(const char *path); -void emu_clear_keydata(void); -uint8_t emu_read_keyfile(struct s_reader *rdr, const char *path); -void emu_read_keymemory(struct s_reader *rdr); - -int8_t is_valid_dcw(uint8_t *dw); -int8_t char_to_bin(uint8_t *out, const char *in, uint32_t inLen); -void date_to_str(char *dateStr, uint8_t len, int8_t offset, uint8_t format); - -KeyDataContainer *emu_get_key_container(char identifier); - -int8_t emu_process_ecm(struct s_reader *rdr, const ECM_REQUEST *er, uint8_t *cw, EXTENDED_CW* cw_ex); - -int8_t emu_process_emm(struct s_reader *rdr, uint16_t caid, const uint8_t *emm, uint32_t *keysAdded); - -int8_t emu_find_key(char identifier, uint32_t provider, uint32_t providerIgnoreMask, char *keyName, - uint8_t *key, uint32_t maxKeyLength, uint8_t isCriticalKey, uint32_t keyRef, - uint8_t matchLength, uint32_t *getProvider); - -int8_t emu_set_key(char identifier, uint32_t provider, char *keyName, uint8_t *orgKey, uint32_t keyLength, - uint8_t writeKey, char *comment, struct s_reader *rdr); - -int8_t emu_update_key(char identifier, uint32_t provider, char *keyName, uint8_t *key, uint32_t keyLength, - uint8_t writeKey, char *comment); - -#endif // WITH_EMU - -#endif // MODULE_EMULATOR_H_ diff --git a/module-emulator-powervu.c b/module-emulator-powervu.c deleted file mode 100755 index 810fcec..0000000 --- a/module-emulator-powervu.c +++ /dev/null @@ -1,2795 +0,0 @@ -#define MODULE_LOG_PREFIX "emu" - -#include "globals.h" - -#ifdef WITH_EMU - -#include "cscrypt/des.h" -#include "module-streamrelay.h" -#include "module-emulator-osemu.h" -#include "module-emulator-powervu.h" -#include "oscam-string.h" -#include "oscam-time.h" - -static inline uint8_t get_bit(uint8_t byte, uint8_t bitnb) -{ - return ((byte & (1 << bitnb)) ? 1 : 0); -} - -static inline uint8_t set_bit(uint8_t val, uint8_t bitnb, uint8_t biton) -{ - return (biton ? (val | (1 << bitnb)) : (val & ~(1 << bitnb))); -} - -static uint8_t crc8_calc(uint8_t *data, int len) -{ - int i; - uint8_t crc = 0; - uint8_t crcTable[256] = - { - 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, - 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, - 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, - 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, - 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, - 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, - 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, - 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, - 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, - 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, - 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, - 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, - 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, - 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, - 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, - 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 - }; - - for (i = 0; i < len; i++) - { - crc = crcTable[data[i] ^ crc]; - } - - return crc; -} - -static void pad_data(uint8_t *data, int len, uint8_t *dataPadded) -{ - int i; - uint8_t pad[] = - { - 0x01, 0x02, 0x22, 0x04, 0x20, 0x2A, 0x1F, 0x03, - 0x04, 0x06, 0x02, 0x0C, 0x2B, 0x2B, 0x01, 0x7B - }; - - for (i = 0; i < len; i++) - { - dataPadded[i] = data[i]; - } - - dataPadded[len] = 0x01; - - for (i = len + 1; i < 0x2F; i++) - { - dataPadded[i] = 0x00; - } - - dataPadded[0x2F] = len; - - for (i = 0; i < 16; i++) - { - dataPadded[0x30 + i] = pad[i]; - } -} - -static void hash_mode_01_custom_md5(uint8_t *data, uint8_t *hash) -{ - int i, j, s; - uint32_t a, b, c, d, f = 0, g; - - uint32_t T[] = - { - 0x783E16F6, 0xC267AC13, 0xA2B17F12, 0x6B8A31A4, - 0xF910654D, 0xB702DBCB, 0x266CEF60, 0x5145E47C, - 0xB92E00D6, 0xE80A4A64, 0x8A07FA77, 0xBA7D89A9, - 0xEBED8022, 0x653AAF2B, 0xF118B03B, 0x6CC16544, - 0x96EB6583, 0xF4E27E35, 0x1ABB119E, 0x068D3EF2, - 0xDAEAA8A5, 0x3C312A3D, 0x59538388, 0xA100772F, - 0xAB0165CE, 0x979959E7, 0x5DD8F53D, 0x189662BA, - 0xFD021A9C, 0x6BC2D338, 0x1EFF667E, 0x40C66888, - 0x6E9F07FF, 0x0CEF442F, 0x82D20190, 0x4E8CAEAC, - 0x0F7CB305, 0x2E73FBE7, 0x1CE884A2, 0x7A60BD52, - 0xC348B30D, 0x081CE3AA, 0xA12220E7, 0x38C7EC79, - 0xCBD8DD3A, 0x62B4FBA5, 0xAD2A63DB, 0xE4D0852E, - 0x53DE980F, 0x9C8DDA59, 0xA6B4CEDE, 0xB48A7692, - 0x0E2C46A4, 0xEB9367CB, 0x165D72EE, 0x75532B45, - 0xB9CA8E97, 0x08C8837B, 0x966F917B, 0x527515B4, - 0xF27A5E5D, 0xB71E6267, 0x7603D7E6, 0x9837DD69 - }; // CUSTOM T - - uint8_t r[] = - { - 0x06, 0x0A, 0x0F, 0x15, 0x05, 0x09, 0x0E, 0x14, - 0x04, 0x0B, 0x10, 0x17, 0x07, 0x0C, 0x11, 0x16 - }; // STANDARD REORDERED - - uint8_t tIdxInit[] = { 0, 1, 5, 0 }; // STANDARD - uint8_t tIdxIncr[] = { 1, 5, 3, 7 }; // STANDARD - - uint32_t h[] = { 0xEAD81D2E, 0xCE4DC6E9, 0xF9B5C301, 0x10325476 }; // CUSTOM h0, h1, h2, STANDARD h3 - uint32_t dataLongs[16]; - - for (i = 0; i < 16; i++) - { - dataLongs[i] = (data[4 * i + 0] << 0) + (data[4 * i + 1] << 8) + - (data[4 * i + 2] << 16) + (data[4 * i + 3] << 24); - } - - a = h[0]; - b = h[1]; - c = h[2]; - d = h[3]; - - for (i = 0; i < 4; i++) - { - g = tIdxInit[i]; - - for (j = 0; j < 16; j++) - { - if (i == 0) - { - f = (b & c) | (~b & d); - } - else if (i == 1) - { - f = (b & d) | (~d & c); - } - else if (i == 2) - { - f = (b ^ c ^ d); - } - else if (i == 3) - { - f = (~d | b) ^ c; - } - - f = dataLongs[g] + a + T[16 * i + j] + f; - - s = r[4 * i + (j & 3)]; - f = (f << s) | (f >> (32 - s)); - - a = d; - d = c; - c = b; - b += f; - - g = (g + tIdxIncr[i]) & 0xF; - } - } - - h[0] += a; - h[1] += b; - h[2] += c; - h[3] += d; - - for (i = 0; i < 4; i++) - { - hash[4 * i + 0] = h[i] >> 0; - hash[4 * i + 1] = h[i] >> 8; - hash[4 * i + 2] = h[i] >> 16; - hash[4 * i + 3] = h[i] >> 24; - } -} - -static void hash_mode_02(uint8_t *data, uint8_t *hash) -{ - int i; - uint32_t a, b, c, d, e, f = 0, tmp; - uint32_t h[] = { 0x81887F3A, 0x36CCA480, 0x99056FB1, 0x79705BAE }; - uint32_t dataLongs[80]; - - for (i = 0; i < 16; i++) - { - dataLongs[i] = (data[4 * i + 0] << 24) + (data[4 * i + 1] << 16) + - (data[4 * i + 2] << 8) + (data[4 * i + 3] << 0); - } - - for (i = 0; i < 64; i++) - { - dataLongs[16 + i] = dataLongs[16 + i - 2]; - dataLongs[16 + i] ^= dataLongs[16 + i - 7]; - dataLongs[16 + i] ^= dataLongs[16 + i - 13]; - dataLongs[16 + i] ^= dataLongs[16 + i - 16]; - } - - a = dataLongs[0]; - b = dataLongs[1]; - c = dataLongs[2]; - d = dataLongs[3]; - e = dataLongs[4]; - - for (i = 0; i < 80; i++) - { - if (i < 0x15) f = (b & c) | (~b & d); - else if (i < 0x28) f = (b ^ c ^ d); - else if (i < 0x3D) f = (b & c) | (c & d) | (b & d); - else if (i < 0x50) f = (b ^ c ^ d); - - tmp = a; - a = e + f + (a << 5) + (a >> 27) + h[i / 0x14] + dataLongs[i]; - e = d; - d = c; - c = (b << 30) + (b >> 2); - b = tmp; - } - - dataLongs[0] += a; - dataLongs[1] += b; - dataLongs[2] += c; - dataLongs[3] += d; - - for (i = 0; i < 4; i++) - { - hash[4 * i + 0] = dataLongs[i] >> 24; - hash[4 * i + 1] = dataLongs[i] >> 16; - hash[4 * i + 2] = dataLongs[i] >> 8; - hash[4 * i + 3] = dataLongs[i] >> 0; - } -} - -static void hash_mode_03(uint8_t *data, uint8_t *hash) -{ - int i, j, k, s, s2, tmp; - uint32_t a, b, c, d, f = 0, g; - uint32_t a2, b2, c2, d2, f2 = 0, g2; - - uint32_t T[] = { 0xC88F3F2E, 0x967506BA, 0xDA877A7B, 0x0DECCDFE }; - uint32_t T2[] = { 0x01F42668, 0x39C7CDA5, 0xD490E2FE, 0x9965235D }; - - uint8_t r[] = - { - 0x0B, 0x0E, 0x0F, 0x0C, 0x05, 0x08, 0x07, 0x09, - 0x0B, 0x0D, 0x0E, 0x0F, 0x06, 0x07, 0x09, 0x08, - 0x07, 0x06, 0x08, 0x0D, 0x0B, 0x09, 0x07, 0x0F, - 0x07, 0x0C, 0x0F, 0x09, 0x0B, 0x07, 0x0D, 0x0C - }; - - uint8_t tIdxIncr[] = - { - 0x07, 0x04, 0x0D, 0x01, 0x0A, 0x06, 0x0F, 0x03, - 0x0C, 0x00, 0x09, 0x05, 0x02, 0x0E, 0x0B, 0x08, - 0x05, 0x0D, 0x02, 0x00, 0x04, 0x09, 0x03, 0x08, - 0x01, 0x0A, 0x07, 0x0B, 0x06, 0x0F, 0x0C, 0x0E - }; - - uint32_t h[] = { 0xC8616857, 0x9D3F5B8E, 0x4D7B8F76, 0x97BC8D80 }; - - uint32_t dataLongs[80]; - uint32_t result[4]; - - for (i = 0; i < 16; i++) - { - dataLongs[i] = (data[4 * i + 0] << 24) + (data[4 * i + 1] << 16) + - (data[4 * i + 2] << 8) + (data[4 * i + 3] << 0); - } - - a = h[0]; - b = h[1]; - c = h[2]; - d = h[3]; - - a2 = h[3]; - b2 = h[2]; - c2 = h[1]; - d2 = h[0]; - - for (i = 0; i < 4; i++) - { - for (j = 0; j < 16; j++) - { - tmp = j; - - for (k = 0; k < i; k++) - { - tmp = tIdxIncr[tmp]; - } - - g = 0x0F - tmp; - g2 = tmp; - - if (i == 0) f = (b & d) | (~d & c); - else if (i == 1) f = (~c | b) ^ d; - else if (i == 2) f = (~b & d) | (b & c); - else if (i == 3) f = (b ^ c ^ d); - - if (i == 0) f2 = (b2 ^ c2 ^ d2); - else if (i == 1) f2 = (~b2 & d2) | (b2 & c2); - else if (i == 2) f2 = (~c2 | b2) ^ d2; - else if (i == 3) f2 = (b2 & d2) | (~d2 & c2); - - f = dataLongs[g] + a + T[i] + f; - s = r[0x0F + (((i & 1) ^ 1) << 4) - j]; - f = (f << s) | (f >> (32 - s)); - - f2 = dataLongs[g2] + a2 + T2[i] + f2; - s2 = r[((i & 1) << 4) + j]; - f2 = (f2 << s2) | (f2 >> (32 - s2)); - - a = d; - d = (c << 10) | (c >> 22); - c = b; - b = f; - - a2 = d2; - d2 = (c2 << 10) | (c2 >> 22); - c2 = b2; - b2 = f2; - } - } - - result[0] = h[3] + b + a2; - result[1] = h[2] + c + b2; - result[2] = h[1] + d + c2; - result[3] = h[0] + a + d2; - - for (i = 0; i < 4; i++) - { - hash[4 * i + 0] = result[i] >> 0; - hash[4 * i + 1] = result[i] >> 8; - hash[4 * i + 2] = result[i] >> 16; - hash[4 * i + 3] = result[i] >> 24; - } -} - -static const uint8_t table04[] = -{ - 0x02, 0x03, 0x07, 0x0B, 0x0D, 0x08, 0x00, 0x01, 0x2B, 0x2D, 0x28, 0x20, 0x21, 0x0A, 0x0C, 0x0E, - 0x22, 0x36, 0x23, 0x27, 0x29, 0x24, 0x25, 0x26, 0x2A, 0x3C, 0x3E, 0x3F, 0x0F, 0x2C, 0x2E, 0x2F, - 0x12, 0x13, 0x17, 0x1B, 0x1C, 0x18, 0x10, 0x11, 0x19, 0x14, 0x15, 0x16, 0x1A, 0x09, 0x04, 0x05, - 0x32, 0x33, 0x37, 0x3B, 0x06, 0x1C, 0x1E, 0x1F, 0x3D, 0x38, 0x30, 0x31, 0x39, 0x34, 0x35, 0x3A -}; - -static const uint8_t table05[] = -{ - 0x08, 0x09, 0x0A, 0x03, 0x04, 0x3F, 0x27, 0x28, 0x29, 0x2A, 0x05, 0x0B, 0x1B, 0x1C, 0x1C, 0x1E, - 0x20, 0x0C, 0x0D, 0x22, 0x23, 0x24, 0x00, 0x01, 0x02, 0x06, 0x07, 0x25, 0x26, 0x0E, 0x0F, 0x21, - 0x10, 0x11, 0x12, 0x2E, 0x2F, 0x13, 0x14, 0x15, 0x2B, 0x2C, 0x2D, 0x16, 0x17, 0x18, 0x19, 0x1A, - 0x30, 0x31, 0x37, 0x3B, 0x3C, 0x3D, 0x3E, 0x1F, 0x38, 0x39, 0x32, 0x33, 0x34, 0x35, 0x36, 0x3A -}; - -static const uint8_t table06[] = -{ - 0x00, 0x01, 0x02, 0x06, 0x07, 0x08, 0x03, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x04, 0x05, 0x09, 0x0D, - 0x20, 0x21, 0x22, 0x26, 0x27, 0x3A, 0x3B, 0x3C, 0x3E, 0x3F, 0x10, 0x11, 0x12, 0x16, 0x17, 0x28, - 0x18, 0x13, 0x14, 0x15, 0x19, 0x1C, 0x1A, 0x1B, 0x1C, 0x1E, 0x1F, 0x23, 0x24, 0x25, 0x29, 0x2D, - 0x30, 0x31, 0x32, 0x36, 0x37, 0x38, 0x33, 0x34, 0x0A, 0x0B, 0x0C, 0x0E, 0x0F, 0x35, 0x39, 0x3D -}; - -static const uint8_t table07[] = -{ - 0x10, 0x11, 0x12, 0x17, 0x1C, 0x1E, 0x0E, 0x38, 0x39, 0x3A, 0x13, 0x14, 0x29, 0x2A, 0x16, 0x1F, - 0x00, 0x01, 0x02, 0x3C, 0x3D, 0x3E, 0x3F, 0x07, 0x08, 0x09, 0x03, 0x04, 0x05, 0x06, 0x3B, 0x0A, - 0x20, 0x21, 0x22, 0x19, 0x1A, 0x1B, 0x1C, 0x0B, 0x0C, 0x15, 0x23, 0x24, 0x25, 0x26, 0x18, 0x0F, - 0x30, 0x31, 0x2B, 0x33, 0x34, 0x35, 0x36, 0x37, 0x27, 0x28, 0x2C, 0x2D, 0x2E, 0x2F, 0x32, 0x0D -}; - -static const uint8_t table08[] = -{ - 0x10, 0x11, 0x1E, 0x17, 0x18, 0x19, 0x12, 0x13, 0x14, 0x1C, 0x1C, 0x15, 0x0D, 0x05, 0x06, 0x0A, - 0x00, 0x01, 0x0E, 0x07, 0x08, 0x09, 0x02, 0x2D, 0x25, 0x26, 0x2A, 0x2B, 0x2F, 0x03, 0x04, 0x0C, - 0x20, 0x21, 0x2E, 0x27, 0x28, 0x29, 0x30, 0x31, 0x3E, 0x37, 0x38, 0x39, 0x22, 0x23, 0x24, 0x2C, - 0x32, 0x33, 0x34, 0x3C, 0x3D, 0x35, 0x36, 0x3A, 0x3B, 0x0B, 0x0F, 0x16, 0x1A, 0x1B, 0x1F, 0x3F -}; - -static const uint8_t table09[] = -{ - 0x20, 0x21, 0x24, 0x22, 0x23, 0x2A, 0x2B, 0x33, 0x35, 0x38, 0x39, 0x36, 0x2D, 0x2C, 0x2E, 0x2F, - 0x00, 0x01, 0x04, 0x02, 0x25, 0x28, 0x08, 0x09, 0x06, 0x07, 0x0A, 0x0B, 0x0D, 0x0C, 0x0E, 0x0F, - 0x10, 0x11, 0x14, 0x12, 0x13, 0x15, 0x19, 0x16, 0x29, 0x26, 0x03, 0x17, 0x1A, 0x1C, 0x1C, 0x1E, - 0x30, 0x31, 0x34, 0x32, 0x37, 0x3A, 0x3B, 0x3D, 0x3C, 0x3E, 0x3F, 0x1B, 0x05, 0x18, 0x27, 0x1F -}; - -static const uint8_t table0A[] = -{ - 0x00, 0x04, 0x05, 0x0B, 0x0C, 0x06, 0x09, 0x0A, 0x0E, 0x0D, 0x0F, 0x25, 0x15, 0x1B, 0x1C, 0x16, - 0x10, 0x11, 0x01, 0x02, 0x03, 0x07, 0x08, 0x12, 0x13, 0x17, 0x18, 0x14, 0x23, 0x27, 0x28, 0x24, - 0x30, 0x31, 0x32, 0x33, 0x37, 0x38, 0x34, 0x35, 0x3B, 0x3C, 0x20, 0x21, 0x22, 0x2B, 0x2C, 0x26, - 0x36, 0x39, 0x3A, 0x3E, 0x3D, 0x19, 0x1A, 0x1E, 0x1C, 0x1F, 0x3F, 0x29, 0x2A, 0x2E, 0x2D, 0x2F -}; - -static void hash_modes_04_to_0A_tables(uint8_t *data, uint8_t *hash, const uint8_t *table) -{ - int i; - - for (i = 0; i < 16; i++) - { - hash[i] = table[i]; - hash[i] ^= data[table[i]]; - hash[i] ^= table[16 + i]; - hash[i] ^= data[table[16 + i]]; - hash[i] ^= table[32 + i]; - hash[i] ^= data[table[32 + i]]; - hash[i] ^= table[48 + i]; - hash[i] ^= data[table[48 + i]]; - } -} - -static const uint8_t table0F[] = { 0xC7, 0x45, 0x15, 0x71, 0x61, 0x07, 0x05, 0x47 }; -static const uint8_t table10[] = { 0x0F, 0x47, 0x2B, 0x6C, 0xAD, 0x0F, 0xB3, 0xEA }; -static const uint8_t table11[] = { 0xB1, 0x46, 0xD1, 0x66, 0x5D, 0x28, 0x59, 0xD2 }; -static const uint8_t table12[] = { 0x0B, 0x4B, 0xD7, 0x68, 0x5F, 0xAD, 0x4B, 0xBB }; -static const uint8_t table13[] = { 0x4F, 0x4E, 0xE1, 0x6A, 0x21, 0xD3, 0xF7, 0xA6 }; -static const uint8_t table14[] = { 0xDD, 0x39, 0xB9, 0x65, 0x03, 0x91, 0xF1, 0xAC }; -static const uint8_t table15[] = { 0x3F, 0x50, 0xB5, 0x6F, 0x37, 0xC9, 0x13, 0x5D }; -static const uint8_t table16[] = { 0xF9, 0x5C, 0xFD, 0x72, 0x19, 0x42, 0x23, 0x6B }; -static const uint8_t table17[] = { 0xDF, 0x60, 0x93, 0x64, 0x33, 0x16, 0xB3, 0x8A }; -static const uint8_t table18[] = { 0x09, 0x64, 0x5F, 0x6B, 0xFB, 0x21, 0x19, 0xE4 }; - -static void hash_modes_0F_to_18_tables(uint8_t *data, uint8_t *hash, const uint8_t *table) -{ - int i; - uint32_t t[4], tmp; - - memset(hash, 0x00, 16); - - t[0] = (table[1] << 8) + table[0]; - t[1] = (table[3] << 8) + table[2]; - t[2] = (table[5] << 8) + table[4]; - t[3] = (table[7] << 8) + table[6]; - - for (i = 0; i < 60; i += 4) - { - t[0] = ((t[0] & 0xFFFF) * t[2]) + (t[0] >> 16); - t[1] = ((t[1] & 0xFFFF) * t[3]) + (t[1] >> 16); - tmp = t[0] + t[1]; - - hash[(i + 0) & 0x0F] = hash[(i + 0) & 0x0F] ^ data[i + 0] ^ (tmp >> 24); - hash[(i + 1) & 0x0F] = hash[(i + 1) & 0x0F] ^ data[i + 1] ^ (tmp >> 16); - hash[(i + 2) & 0x0F] = hash[(i + 2) & 0x0F] ^ data[i + 2] ^ (tmp >> 8); - hash[(i + 3) & 0x0F] = hash[(i + 3) & 0x0F] ^ data[i + 3] ^ (tmp >> 0); - } -} - -static const uint8_t table19[] = { 0x02, 0x03, 0x05, 0x10 }; -static const uint8_t table1A[] = { 0x01, 0x05, 0x08, 0x10 }; -static const uint8_t table1B[] = { 0x03, 0x07, 0x08, 0x10 }; -static const uint8_t table1C[] = { 0x03, 0x05, 0x0A, 0x10 }; -static const uint8_t table1D[] = { 0x03, 0x07, 0x0A, 0x10 }; -static const uint8_t table1E[] = { 0x01, 0x05, 0x0B, 0x10 }; -static const uint8_t table1F[] = { 0x06, 0x07, 0x0B, 0x10 }; -static const uint8_t table20[] = { 0x01, 0x08, 0x0B, 0x10 }; -static const uint8_t table21[] = { 0x01, 0x07, 0x0C, 0x10 }; -static const uint8_t table22[] = { 0x05, 0x0B, 0x0C, 0x10 }; -static const uint8_t table23[] = { 0x0B, 0x0C, 0x0D, 0x10 }; -static const uint8_t table24[] = { 0x07, 0x09, 0x0E, 0x10 }; -static const uint8_t table25[] = { 0x01, 0x04, 0x0F, 0x10 }; -static const uint8_t table26[] = { 0x07, 0x08, 0x0F, 0x10 }; -static const uint8_t table27[] = { 0x02, 0x0B, 0x0F, 0x10 }; - -static void hash_modes_19_to_27_tables_3(uint8_t *data, uint8_t *hash, const uint8_t *table) -{ - int i; - uint8_t val, it[4]; - uint16_t seed = 0xFFFF, tmp; - - memset(hash, 0x00, 16); - - for (i = 0; i < 4; i++) - { - it[i] = 0x10 - table[i]; - } - - for (i = 0; i < 16; i++) - { - val = ((seed >> it[0]) ^ (seed >> it[1]) ^ (seed >> it[2]) ^ (seed >> it[3])) & 0x01; - - if (val == 0x00) - { - seed = seed >> 1; - } - else - { - seed = (seed >> 1) | 0x8000; - } - tmp = seed + (data[i] << 8) + data[i + 32]; - - val = ((seed >> it[0]) ^ (seed >> it[1]) ^ (seed >> it[2]) ^ (seed >> it[3])) & 0x01; - - if (val == 0x00) - { - seed = seed >> 1; - } - else - { - seed = (seed >> 1) | 0x8000; - } - tmp = tmp + seed + (data[i + 16] << 8) + data[i + 48]; - - hash[i & 0x0F] ^= tmp >> 8; - hash[(i + 1) & 0x0F] ^= tmp; - } -} - -static void create_hash(uint8_t *data, int len, uint8_t *hash, int mode) -{ - if ((mode > 0x27) || (mode == 0x0B) || (mode == 0x0C) || - (mode == 0x0D) || (mode == 0x0E) || (mode == 0)) - { - memset(hash, 0, 16); - return; - } - - uint8_t dataPadded[64]; - - pad_data(data, len, dataPadded); - - switch (mode) - { - case 1: - hash_mode_01_custom_md5(dataPadded, hash); - break; - - case 2: - hash_mode_02(dataPadded, hash); - break; - - case 3: - hash_mode_03(dataPadded, hash); - break; - - case 4: - hash_modes_04_to_0A_tables(dataPadded, hash, table04); - break; - - case 5: - hash_modes_04_to_0A_tables(dataPadded, hash, table05); - break; - - case 6: - hash_modes_04_to_0A_tables(dataPadded, hash, table06); - break; - - case 7: - hash_modes_04_to_0A_tables(dataPadded, hash, table07); - break; - - case 8: - hash_modes_04_to_0A_tables(dataPadded, hash, table08); - break; - - case 9: - hash_modes_04_to_0A_tables(dataPadded, hash, table09); - break; - - case 10: - hash_modes_04_to_0A_tables(dataPadded, hash, table0A); - break; - - case 15: - hash_modes_0F_to_18_tables(dataPadded, hash, table0F); - break; - - case 16: - hash_modes_0F_to_18_tables(dataPadded, hash, table10); - break; - - case 17: - hash_modes_0F_to_18_tables(dataPadded, hash, table11); - break; - - case 18: - hash_modes_0F_to_18_tables(dataPadded, hash, table12); - break; - - case 19: - hash_modes_0F_to_18_tables(dataPadded, hash, table13); - break; - - case 20: - hash_modes_0F_to_18_tables(dataPadded, hash, table14); - break; - - case 21: - hash_modes_0F_to_18_tables(dataPadded, hash, table15); - break; - - case 22: - hash_modes_0F_to_18_tables(dataPadded, hash, table16); - break; - - case 23: - hash_modes_0F_to_18_tables(dataPadded, hash, table17); - break; - - case 24: - hash_modes_0F_to_18_tables(dataPadded, hash, table18); - break; - - case 25: - hash_modes_19_to_27_tables_3(dataPadded, hash, table19); - break; - - case 26: - hash_modes_19_to_27_tables_3(dataPadded, hash, table1A); - break; - - case 27: - hash_modes_19_to_27_tables_3(dataPadded, hash, table1B); - break; - - case 28: - hash_modes_19_to_27_tables_3(dataPadded, hash, table1C); - break; - - case 29: - hash_modes_19_to_27_tables_3(dataPadded, hash, table1D); - break; - - case 30: - hash_modes_19_to_27_tables_3(dataPadded, hash, table1E); - break; - - case 31: - hash_modes_19_to_27_tables_3(dataPadded, hash, table1F); - break; - - case 32: - hash_modes_19_to_27_tables_3(dataPadded, hash, table20); - break; - - case 33: - hash_modes_19_to_27_tables_3(dataPadded, hash, table21); - break; - - case 34: - hash_modes_19_to_27_tables_3(dataPadded, hash, table22); - break; - - case 35: - hash_modes_19_to_27_tables_3(dataPadded, hash, table23); - break; - - case 36: - hash_modes_19_to_27_tables_3(dataPadded, hash, table24); - break; - - case 37: - hash_modes_19_to_27_tables_3(dataPadded, hash, table25); - break; - - case 38: - hash_modes_19_to_27_tables_3(dataPadded, hash, table26); - break; - - case 39: - hash_modes_19_to_27_tables_3(dataPadded, hash, table27); - break; - - default: - cs_log("A new hash mode [%d] is in use.", mode); - break; - } -} - -static void create_hash_mode_03(uint8_t *data, uint8_t *hash) -{ - int i, j, c; - uint8_t buffer0[16], buffer1[8], buffer2[8], tmpBuff1[4], tmpBuff2[4]; - - uint8_t table[] = - { - 0x68, 0xCE, 0xE7, 0x71, 0xCC, 0x3A, 0x0B, 0x6E, 0x2A, 0x43, 0x17, 0x07, 0x5A, 0xD9, 0x14, 0x5B, - 0xB0, 0x8E, 0xA8, 0x7F, 0xD8, 0xA2, 0xCF, 0x73, 0xC2, 0xB9, 0x5D, 0x46, 0xDD, 0x2C, 0xE2, 0x2D, - 0xFD, 0x50, 0xE9, 0x7C, 0x28, 0x72, 0x9B, 0xAA, 0xEC, 0x24, 0x74, 0xAB, 0x00, 0x1C, 0x8B, 0x65, - 0x38, 0x13, 0x22, 0x82, 0xAC, 0x9A, 0x4D, 0x2B, 0xEA, 0x04, 0x31, 0x84, 0x32, 0x3D, 0x36, 0x53, - 0x5F, 0x42, 0x96, 0xDE, 0x47, 0x08, 0x51, 0x4B, 0x3E, 0xD1, 0x1E, 0x12, 0xD2, 0x1F, 0x7D, 0x26, - 0xCD, 0x57, 0x8C, 0xB6, 0xD3, 0xF8, 0x11, 0xAD, 0x6A, 0x88, 0x95, 0x21, 0xE8, 0xBF, 0x6B, 0x27, - 0xBE, 0xA3, 0x33, 0xB8, 0x9E, 0xB3, 0x6C, 0xC3, 0x06, 0xC7, 0x6F, 0x99, 0x97, 0xDA, 0x09, 0xAF, - 0xAE, 0xCB, 0x79, 0x37, 0x55, 0x85, 0x8D, 0x2F, 0x8A, 0x70, 0xA1, 0x7A, 0x66, 0x29, 0x67, 0x0F, - 0xEB, 0x9C, 0xC8, 0xC4, 0xD6, 0x4C, 0xDF, 0x1A, 0xC0, 0x01, 0x64, 0xBC, 0x4E, 0xE1, 0x54, 0xD7, - 0x4F, 0xB7, 0x5E, 0xCA, 0xF0, 0x91, 0xE4, 0x59, 0x4A, 0xC6, 0x83, 0x8F, 0xBD, 0x61, 0xFF, 0x56, - 0x92, 0xF1, 0x5C, 0x77, 0xC9, 0x20, 0xF4, 0xE5, 0x10, 0x69, 0x03, 0x1D, 0xD5, 0x45, 0xF6, 0x0E, - 0xEF, 0xA0, 0xE3, 0x58, 0xFC, 0xED, 0x80, 0x16, 0xEE, 0xFA, 0x02, 0xF5, 0xB4, 0x0A, 0xE0, 0x0C, - 0xF7, 0xF9, 0xBA, 0x7E, 0x18, 0x78, 0x19, 0xB5, 0x0D, 0x44, 0x34, 0xD4, 0xDC, 0x30, 0x6D, 0x3B, - 0x63, 0x41, 0x48, 0x40, 0xA7, 0xA5, 0xC5, 0x98, 0x76, 0x3F, 0xC1, 0x25, 0x93, 0x49, 0xD0, 0x62, - 0x2E, 0x75, 0xDB, 0x94, 0xF3, 0x52, 0x05, 0x81, 0xFB, 0xBB, 0xA6, 0x89, 0x39, 0xA4, 0xF2, 0xA9, - 0xFE, 0x60, 0x3C, 0x15, 0xB1, 0x35, 0x86, 0x9D, 0x9F, 0x90, 0x1B, 0xE6, 0x7B, 0x23, 0x87, 0xB2 - }; - - for (i = 0; i < 4; i++) - { - buffer0[0 + i] = data[12 + i]; - buffer0[4 + i] = data[8 + i]; - buffer0[8 + i] = data[4 + i]; - buffer0[12 + i] = data[0 + i]; - } - - for (c = 0; c < 12; c++) - { - for (i = 0; i < 4; i++) - { - buffer1[0 + i] = buffer0[8 + i] ^ buffer0[12 + i]; - buffer1[4 + i] = buffer0[0 + i] ^ buffer0[4 + i]; - } - - for (i = 0; i < 8; i++) - { - buffer1[i] = table[buffer1[i] ^ data[16 + 16 * (c % 3) + i]]; - } - - for (j = 0; j < 8; j++) - { - buffer2[j] = 0; - for (i = 0; i < 8; i++) - { - buffer2[j] ^= buffer1[i] * (j * i + 1); - } - } - - for (i = 0; i < 8; i++) - { - buffer2[i] = table[buffer2[i] ^ data[24 + 16 * (c % 3) + i]] ^ data[16 + 16 * (c % 3) + i]; - } - - for (i = 0; i < 4; i++) - { - buffer0[12 + i] ^= buffer2[0 + i]; - buffer0[8 + i] ^= buffer2[0 + i]; - buffer0[4 + i] ^= buffer2[4 + i]; - buffer0[0 + i] ^= buffer2[4 + i]; - } - - tmpBuff1[0] = buffer0[14]; - tmpBuff1[1] = buffer0[15]; - tmpBuff1[2] = buffer0[12] ^ buffer0[14]; - tmpBuff1[3] = buffer0[13] ^ buffer0[15]; - - tmpBuff2[0] = buffer0[6]; - tmpBuff2[1] = buffer0[7]; - tmpBuff2[2] = buffer0[4] ^ buffer0[6]; - tmpBuff2[3] = buffer0[5] ^ buffer0[7]; - - for (i = 0; i < 4; i++) - { - buffer0[12 + i] = tmpBuff1[i]; - buffer0[4 + i] = tmpBuff2[i]; - } - } - - for (i = 0; i < 4; i++) - { - hash[0 + i] = buffer0[12 + i] ^ data[0 + i]; - hash[4 + i] = buffer0[8 + i] ^ data[4 + i]; - hash[8 + i] = buffer0[4 + i] ^ data[8 + i]; - hash[12 + i] = buffer0[0 + i] ^ data[12 + i]; - } -} - -static void create_data_cw_mode_03(uint8_t *seed, int lenSeed, uint8_t *basecw, - uint8_t val, uint8_t *ecmBody, uint8_t *data) -{ - int idxData = 8, idxSeed = 0, idxBase = 0; - uint8_t padding[] = - { - 0x4A, 0x56, 0x7F, 0x16, 0xFC, 0x1F, 0x5B, 0x95, - 0x19, 0xEF, 0x75, 0x14, 0x0E, 0x9E, 0x17, 0x3C, - 0xF5, 0xB7, 0xA0, 0x93, 0xA3, 0x0F, 0xFA, 0x38, - 0x7A, 0x34, 0x6C, 0xDC, 0xFB, 0xB0, 0x24, 0x42, - 0x74, 0x72, 0x1C, 0xDC, 0x1E, 0xA1, 0x6D, 0xAB, - 0xC8, 0x44, 0x53, 0xEF, 0x56, 0x00, 0xE9, 0x97, - 0x48, 0x77, 0xF8, 0x00, 0x8E, 0x0B, 0x78, 0xA2 - }; - - memcpy(data + 8, padding, 56); - - data[0] = ecmBody[0x0F]; - data[1] = ecmBody[0x09]; - data[2] = ecmBody[0x10]; - data[3] = ecmBody[0x11]; - data[4] = ecmBody[0x05]; - data[5] = ecmBody[0x07]; - data[6] = ecmBody[0x08]; - data[7] = ecmBody[0x0A]; - - while (idxBase < 7) - { - if ((idxBase == 0) || (idxBase == 2) || (idxBase == 5)) - { - data[idxData++] = val; - } - - if (idxSeed < lenSeed) - { - data[idxData++] = seed[idxSeed++]; - } - - data[idxData++] = basecw[idxBase++]; - } -} - -static void create_data_unmask_mode_03(uint8_t *ecmBody, uint8_t *data) -{ - uint8_t padding[] = - { - 0xB1, 0x7C, 0xD2, 0xA7, 0x5E, 0x45, 0x6C, 0x36, - 0xF0, 0xB6, 0x81, 0xF3, 0x25, 0x06, 0x65, 0x06, - 0x6B, 0xBF, 0x4C, 0xE7, 0xED, 0x6E, 0x85, 0x00, - 0xCC, 0xF2, 0x61, 0x48, 0x62, 0x24, 0x0E, 0x3C, - 0x05, 0x89, 0xA5, 0x39, 0x5A, 0x4E, 0x9B, 0xC8, - 0x14, 0x78, 0xEA, 0xB6, 0xFB, 0xF8, 0x10, 0xE6, - 0x61, 0xF5, 0x3A, 0xBC, 0x5B, 0x79, 0x09, 0x97 - }; - - memcpy(data + 8, padding, 56); - - data[0] = ecmBody[0x17]; - data[1] = ecmBody[0x26]; - data[2] = ecmBody[0x19]; - data[3] = ecmBody[0x21]; - data[4] = ecmBody[0x26]; - data[5] = ecmBody[0x31]; - data[6] = ecmBody[0x21]; - data[7] = ecmBody[0x27]; -} - -static void hash_04_add(uint32_t *buffer, int a, int b, int c, int d, int e, int f) -{ - uint32_t tmp1 = (buffer[a] & 1) + (buffer[b] & 1); - uint32_t tmp2 = (buffer[a] >> 1) + (buffer[b] >> 1) + (tmp1 >> 1); - - buffer[e] = buffer[c] + buffer[d] + (tmp2 >> 31); - buffer[f] = tmp2 + tmp2 + (tmp1 & 1); -} - -static void hash_04_shift(uint32_t *buffer, int a, int b, uint8_t shift) -{ - uint32_t tmp1 = (buffer[a] >> (32 - shift)) + (buffer[b] << shift); - uint32_t tmp2 = (buffer[b] >> (32 - shift)) + (buffer[a] << shift); - - buffer[b] = tmp1; - buffer[a] = tmp2; -} - -static void hash_04_xor(uint32_t *buffer, int a, int b, int c, int d) -{ - buffer[a] ^= buffer[b]; - buffer[c] ^= buffer[d]; -} - -static void hash_04_swap(uint32_t *buffer, int a, int b) -{ - uint32_t tmp = buffer[a]; - - buffer[a] = buffer[b]; - buffer[b] = tmp; -} - -static void hash_04_core(uint32_t *buffer) -{ - hash_04_add(buffer, 0, 6, 7, 1, 7, 6); - hash_04_shift(buffer, 5, 4, 0x0D); - hash_04_xor(buffer, 4, 2, 5, 3); - hash_04_swap(buffer, 7, 6); - hash_04_add(buffer, 6, 2, 3, 7, 3, 2); - hash_04_shift(buffer, 1, 0, 0x10); - hash_04_xor(buffer, 0, 4, 1, 5); - hash_04_add(buffer, 6, 2, 3, 7, 7, 6); - hash_04_shift(buffer, 1, 0, 0x15); - hash_04_add(buffer, 6, 0, 1, 7, 1, 0); - hash_04_xor(buffer, 2, 4, 3, 5); - hash_04_shift(buffer, 5, 4, 0x11); - hash_04_xor(buffer, 4, 2, 5, 3); - hash_04_swap(buffer, 3, 2); -} - -static void create_hash_mode_04(uint8_t *data, uint8_t *hash) -{ - int i, j; - uint32_t d0, d1, h0, h1, h2, h3; - uint32_t buffer[] = - { - 0x1F253724, 0x3E8136B3, 0x9677CEDF, 0x25B5E75A, - 0x9494BC16, 0xCFD3FB34, 0xF37C75BB, 0x97D4632E - }; - - for (j = 0; j < 64; j += 8) - { - d0 = (data[j + 3] << 24) + (data[j + 2] << 16) + (data[j + 1] << 8) + data[j + 0]; - d1 = (data[j + 7] << 24) + (data[j + 6] << 16) + (data[j + 5] << 8) + data[j + 4]; - - buffer[0] ^= d0; - buffer[1] ^= d1; - - for (i = 0; i < 2; i++) - { - hash_04_core(buffer); - } - - buffer[6] ^= d0; - buffer[7] ^= d1; - } - - buffer[1] ^= 0x40000000; - buffer[0] ^= 0x00000000; - - for (i = 0; i < 2; i++) - { - hash_04_core(buffer); - } - - buffer[7] ^= 0x40000000; - buffer[6] ^= 0x00000000; - buffer[2] ^= 0xEE; - - for (i = 0; i < 4; i++) - { - hash_04_core(buffer); - } - - h0 = buffer[0] ^ buffer[2] ^ buffer[4] ^ buffer[6]; - h1 = buffer[1] ^ buffer[3] ^ buffer[5] ^ buffer[7]; - - hash[0] = (uint8_t) h0; - hash[1] = (uint8_t) (h0 >> 8); - hash[2] = (uint8_t) (h0 >> 16); - hash[3] = (uint8_t) (h0 >> 24); - hash[4] = (uint8_t) h1; - hash[5] = (uint8_t) (h1 >> 8); - hash[6] = (uint8_t) (h1 >> 16); - hash[7] = (uint8_t) (h1 >> 24); - - buffer[4] ^= 0xDD; - - for (i = 0; i < 4; i++) - { - hash_04_core(buffer); - } - - h2 = buffer[0] ^ buffer[2] ^ buffer[4] ^ buffer[6]; - h3 = buffer[1] ^ buffer[3] ^ buffer[5] ^ buffer[7]; - - hash[8] = (uint8_t) h2; - hash[9] = (uint8_t) (h2 >> 8); - hash[10] = (uint8_t) (h2 >> 16); - hash[11] = (uint8_t) (h2 >> 24); - hash[12] = (uint8_t) h3; - hash[13] = (uint8_t) (h3 >> 8); - hash[14] = (uint8_t) (h3 >> 16); - hash[15] = (uint8_t) (h3 >> 24); -} - -static void create_data_cw_mode_04(uint8_t *seed, int lenSeed, uint8_t *basecw, - uint8_t val, uint8_t *ecmBody, uint8_t *data) -{ - uint8_t padding[] = - { - 0x18, 0xD6, 0x24, 0xA8, 0xDE, 0x14, 0xD8, 0x30, - 0x3C, 0xB2, 0x24, 0x54, 0x17, 0x5A, 0x28, 0x61, - 0xBC, 0xB9, 0x29, 0xAD, 0xA5, 0x13, 0xD4, 0x24, - 0x6D, 0x61, 0x40, 0xC8, 0xFD, 0x27, 0xD7, 0xFF, - 0x3E, 0x84, 0x50, 0xC2, 0x47, 0x4C, 0xD5, 0xC5, - 0xF2, 0x79, 0xAD, 0x02, 0xC5, 0x05, 0x7B, 0xFD, - 0x60, 0x4A, 0x16, 0xE5, 0xAA, 0x0E, 0x97, 0x1C - }; - - memcpy(data + 8, padding, 56); - - data[0] = ecmBody[0x0E]; - data[1] = ecmBody[0x0A]; - data[2] = ecmBody[0x0C]; - data[3] = ecmBody[0x04]; - data[4] = ecmBody[0x10]; - data[5] = ecmBody[0x08]; - data[6] = ecmBody[0x05]; - data[7] = ecmBody[0x0F]; - - int idxData = 8, idxSeed = 0, idxBase = 0; - - while (idxBase < 7) - { - if ((idxBase == 0) || (idxBase == 1) || (idxBase == 2)) - { - data[idxData++] = val; - } - - if (idxSeed < lenSeed) - { - data[idxData++] = seed[idxSeed++]; - } - - data[idxData++] = basecw[idxBase++]; - } -} - -static void create_data_unmask_mode_04(uint8_t *ecmBody, uint8_t *data) -{ - uint8_t padding[] = - { - 0x0E, 0x4A, 0x85, 0x85, 0xF9, 0xC0, 0xCC, 0x00, - 0xBA, 0x9B, 0x98, 0x35, 0x4C, 0xD2, 0xC1, 0x6C, - 0x87, 0x32, 0x9B, 0x82, 0x31, 0x5B, 0x1D, 0xB4, - 0xB8, 0x98, 0x74, 0xFF, 0x31, 0x66, 0x08, 0x79, - 0x47, 0xCE, 0x96, 0x4D, 0xE9, 0x52, 0xCF, 0x8F, - 0xEC, 0x5C, 0x07, 0xBC, 0x09, 0xA2, 0x82, 0x78, - 0x3D, 0xB9, 0xFF, 0x3F, 0x76, 0x72, 0x6F, 0x9C - }; - - memcpy(data + 8, padding, 56); - - data[0] = ecmBody[0x17]; - data[1] = ecmBody[0x2B]; - data[2] = ecmBody[0x1D]; - data[3] = ecmBody[0x2D]; - data[4] = ecmBody[0x0B]; - data[5] = ecmBody[0x06]; - data[6] = ecmBody[0x2F]; - data[7] = ecmBody[0x1E]; -} - -static uint8_t get_mode_cw(uint8_t *extraData) -{ - uint64_t data = ((uint32_t)extraData[0] << 24) + (extraData[1] << 16) + (extraData[2] << 8) + extraData[3]; - uint64_t t1 = (data * 0x76E9DEA7) >> 50; - uint64_t t2 = (t1 * 0x51EB851F) >> 36; - uint64_t t3 = t2 * 0x32; - uint8_t r = t1 - t3; - return r; -} - -static uint8_t get_mode_unmask(uint8_t *extraData) -{ - uint64_t data = ((uint32_t)extraData[0] << 24) + (extraData[1] << 16) + (extraData[2] << 8) + extraData[3]; - uint64_t t1 = (data * 0xB9CD6BE5) >> 45; - uint64_t t2 = (t1 * 0x51EB851F) >> 36; - uint64_t t3 = t2 * 0x32; - uint8_t r = t1 - t3; - return r; -} - -static void create_data_ecm_emm(uint8_t *emmEcm, uint8_t *pos, int lenHeader, int len, uint8_t *data) -{ - int i; - - for (i = 0; i < len; i++) - { - data[i] = emmEcm[lenHeader + pos[i]]; - } -} - -static uint8_t create_data_cw(uint8_t *seed, uint8_t lenSeed, uint8_t *baseCw, - uint8_t val, uint8_t *seedEcmCw, uint8_t *data) -{ - int i; - - for (i = 0; i < lenSeed; i++) - { - data[i] = seed[i]; - } - - for (i = 0; i < 7; i++) - { - data[lenSeed + i] = baseCw[i]; - } - - data[lenSeed + 7] = val; - - for (i = 0; i < 16; i++) - { - data[lenSeed + 7 + 1 + i] = seedEcmCw[i]; - } - - return lenSeed + 7 + 1 + 0x10; -} - -static uint8_t unmask_ecm(uint8_t *ecm, uint8_t *seedEcmCw, uint8_t *modeCW) -{ - int i, l; - uint8_t data[64], mask[16]; - uint8_t hashModeEcm, hashModeCw, modeUnmask = 0; - uint32_t crc; - - uint8_t sourcePos[] = - { - 0x04, 0x05, 0x06, 0x07, 0x0A, 0x0B, 0x0C, 0x0D, - 0x0E, 0x0F, 0x10, 0x17, 0x1C, 0x1D, 0x1F, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x29, 0x2C, 0x2D, 0x2E - }; - - uint8_t destPos[] = - { - 0x08, 0x09, 0x11, 0x18, 0x19, 0x1A, 0x1B, 0x1E, - 0x20, 0x21, 0x22, 0x28, 0x2A, 0x2B, 0x2F, 0x30 - }; - - uint8_t seedCwPos[] = { 0x07, 0x0A, 0x04, 0x0D, 0x05, 0x0E, 0x06, 0x0B, 0x10, 0x0C, 0x0F }; - - // Create seed for CW decryption - memset(seedEcmCw, 0, 16); - - int extraBytesLen = ecm[9]; - int startOffset = extraBytesLen + 10; - - for (i = 0; i < 11; i++) - { - seedEcmCw[i] = ecm[startOffset + seedCwPos[i]]; - } - - *modeCW = 0; - if (extraBytesLen > 0) - { - *modeCW = get_mode_cw(ecm + 10); - } - - // Read hash mode CW - hashModeCw = ecm[28 + extraBytesLen] ^ crc8_calc(seedEcmCw, 16); - - // Create mask for ECM decryption - create_data_ecm_emm(ecm, sourcePos, startOffset, 24, data); - - hashModeEcm = ecm[8] ^ crc8_calc(data, 24); - - if (extraBytesLen > 0) - { - modeUnmask = get_mode_unmask(ecm + 10); - } - - if (modeUnmask == 0x03) - { - ecm[startOffset + 0x21] -= ecm[startOffset + 0x07]; - ecm[startOffset + 0x26] -= ecm[startOffset + 0x05]; - ecm[startOffset + 0x26] -= ecm[startOffset + 0x08]; - ecm[startOffset + 0x19] -= ecm[startOffset + 0x06]; - ecm[startOffset + 0x31] -= ecm[startOffset + 0x09]; - ecm[startOffset + 0x27] -= ecm[startOffset + 0x0C]; - ecm[startOffset + 0x21] -= ecm[startOffset + 0x0B]; - ecm[startOffset + 0x17] -= ecm[startOffset + 0x04]; - - create_data_unmask_mode_03(ecm + startOffset, data); - create_hash_mode_03(data, mask); - - // Unmask body - ecm[startOffset + 0x06] ^= mask[0x02]; - ecm[startOffset + 0x0B] ^= mask[0x06]; - ecm[startOffset + 0x0C] ^= mask[0x07]; - ecm[startOffset + 0x0D] ^= mask[0x08]; - ecm[startOffset + 0x0E] ^= mask[0x09]; - ecm[startOffset + 0x0F] ^= mask[0x0A]; - ecm[startOffset + 0x11] ^= mask[0x0B]; - ecm[startOffset + 0x18] ^= mask[0x0C]; - ecm[startOffset + 0x2D] ^= mask[0x0A]; - ecm[startOffset + 0x07] ^= mask[0x03]; - ecm[startOffset + 0x1B] ^= mask[0x0D]; - ecm[startOffset + 0x30] ^= mask[0x0C]; - ecm[startOffset + 0x1C] ^= mask[0x0E]; - ecm[startOffset + 0x1E] ^= mask[0x00]; - ecm[startOffset + 0x04] ^= mask[0x00]; - ecm[startOffset + 0x05] ^= mask[0x01]; - ecm[startOffset + 0x1F] ^= mask[0x01]; - ecm[startOffset + 0x2C] ^= mask[0x09]; - ecm[startOffset + 0x20] ^= mask[0x02]; - ecm[startOffset + 0x1D] ^= mask[0x0F]; - ecm[startOffset + 0x23] ^= mask[0x04]; - ecm[startOffset + 0x09] ^= mask[0x05]; - ecm[startOffset + 0x22] ^= mask[0x03]; - ecm[startOffset + 0x24] ^= mask[0x05]; - ecm[startOffset + 0x08] ^= mask[0x04]; - ecm[startOffset + 0x28] ^= mask[0x06]; - ecm[startOffset + 0x29] ^= mask[0x07]; - ecm[startOffset + 0x2A] ^= mask[0x08]; - ecm[startOffset + 0x2E] ^= mask[0x0B]; - - for (i = 0; i < ecm[9]; i++) - { - ecm[10 + i] = 0x00; - } - } - else if (modeUnmask == 0x04) - { - ecm[startOffset + 0x1E] -= ecm[startOffset + 0x0D]; - ecm[startOffset + 0x1D] -= ecm[startOffset + 0x07]; - ecm[startOffset + 0x2B] -= ecm[startOffset + 0x05]; - ecm[startOffset + 0x2D] -= ecm[startOffset + 0x08]; - ecm[startOffset + 0x17] -= ecm[startOffset + 0x04]; - ecm[startOffset + 0x2F] -= ecm[startOffset + 0x0C]; - ecm[startOffset + 0x06] -= ecm[startOffset + 0x0A]; - ecm[startOffset + 0x0B] -= ecm[startOffset + 0x09]; - - create_data_unmask_mode_04(ecm + startOffset, data); - create_hash_mode_04(data, mask); - - // Unmask body - ecm[startOffset + 0x04] ^= mask[0x00]; - ecm[startOffset + 0x05] ^= mask[0x01]; - ecm[startOffset + 0x07] ^= mask[0x02]; - ecm[startOffset + 0x08] ^= mask[0x03]; - ecm[startOffset + 0x09] ^= mask[0x04]; - ecm[startOffset + 0x0A] ^= mask[0x05]; - ecm[startOffset + 0x0C] ^= mask[0x06]; - ecm[startOffset + 0x0D] ^= mask[0x07]; - ecm[startOffset + 0x0E] ^= mask[0x08]; - ecm[startOffset + 0x10] ^= mask[0x09]; - ecm[startOffset + 0x11] ^= mask[0x0A]; - ecm[startOffset + 0x18] ^= mask[0x0B]; - ecm[startOffset + 0x1A] ^= mask[0x0C]; - ecm[startOffset + 0x1B] ^= mask[0x0D]; - ecm[startOffset + 0x1C] ^= mask[0x0E]; - ecm[startOffset + 0x1F] ^= mask[0x0F]; - ecm[startOffset + 0x22] ^= mask[0x00]; - ecm[startOffset + 0x24] ^= mask[0x01]; - ecm[startOffset + 0x25] ^= mask[0x02]; - ecm[startOffset + 0x26] ^= mask[0x03]; - ecm[startOffset + 0x27] ^= mask[0x04]; - ecm[startOffset + 0x28] ^= mask[0x05]; - ecm[startOffset + 0x29] ^= mask[0x06]; - ecm[startOffset + 0x2A] ^= mask[0x07]; - ecm[startOffset + 0x2C] ^= mask[0x08]; - ecm[startOffset + 0x2E] ^= mask[0x09]; - ecm[startOffset + 0x31] ^= mask[0x0A]; - - for (i = 0; i < ecm[9]; i++) - { - ecm[10 + i] = 0x00; - } - } - else - { - create_hash(data, 24, mask, hashModeEcm); - - // Unmask body - for (i = 0; i < 16; i++) - { - ecm[startOffset + destPos[i]] ^= mask[i & 0x0F]; - } - } - - // Fix header - ecm[3] &= 0x0F; - ecm[3] |= 0x30; - ecm[8] = 0x00; - ecm[28 + extraBytesLen] = 0x00; - - // Fix CRC (optional) - l = (((ecm[1] << 8) + ecm[2]) & 0xFFF) + 3 - 4; - - crc = ccitt32_crc(ecm, l); - - ecm[l + 0] = crc >> 24; - ecm[l + 1] = crc >> 16; - ecm[l + 2] = crc >> 8; - ecm[l + 3] = crc >> 0; - - for (i = 0; i < 11; i++) - { - seedEcmCw[i] = ecm[startOffset + seedCwPos[i]]; - } - - return hashModeCw; -} - -static void create_cw(uint8_t *seed, uint8_t lenSeed, uint8_t *baseCw, uint8_t val, uint8_t *seedEcmCw, - uint8_t *cw, int modeDesCsa, int hashMode, int modeCW, uint8_t *ecmBody) -{ - int i; - uint8_t data[64], hash[16], lenData; - uint8_t tableFixParity[] = - { - 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07, - 0x08, 0x08, 0x0B, 0x0B, 0x0D, 0x0D, 0x0E, 0x0E, - 0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16, - 0x19, 0x19, 0x1A, 0x1A, 0x1C, 0x1C, 0x1F, 0x1F, - 0x20, 0x20, 0x23, 0x23, 0x25, 0x25, 0x26, 0x26, - 0x29, 0x29, 0x2A, 0x2A, 0x2C, 0x2C, 0x2F, 0x2F, - 0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37, - 0x38, 0x38, 0x3B, 0x3B, 0x3D, 0x3D, 0x3E, 0x3E, - 0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46, - 0x49, 0x49, 0x4A, 0x4A, 0x4C, 0x4C, 0x4F, 0x4F, - 0x51, 0x51, 0x52, 0x52, 0x54, 0x54, 0x57, 0x57, - 0x58, 0x58, 0x5B, 0x5B, 0x5D, 0x5D, 0x5E, 0x5E, - 0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67, - 0x68, 0x68, 0x6B, 0x6B, 0x6D, 0x6D, 0x6E, 0x6E, - 0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76, - 0x79, 0x79, 0x7A, 0x7A, 0x7C, 0x7C, 0x7F, 0x7F, - 0x80, 0x80, 0x83, 0x83, 0x85, 0x85, 0x86, 0x86, - 0x89, 0x89, 0x8A, 0x8A, 0x8C, 0x8C, 0x8F, 0x8F, - 0x91, 0x91, 0x92, 0x92, 0x94, 0x94, 0x97, 0x97, - 0x98, 0x98, 0x9B, 0x9B, 0x9D, 0x9D, 0x9E, 0x9E, - 0xA1, 0xA1, 0xA2, 0xA2, 0xA4, 0xA4, 0xA7, 0xA7, - 0xA8, 0xA8, 0xAB, 0xAB, 0xAD, 0xAD, 0xAE, 0xAE, - 0xB0, 0xB0, 0xB3, 0xB3, 0xB5, 0xB5, 0xB6, 0xB6, - 0xB9, 0xB9, 0xBA, 0xBA, 0xBC, 0xBC, 0xBF, 0xBF, - 0xC1, 0xC1, 0xC2, 0xC2, 0xC4, 0xC4, 0xC7, 0xC7, - 0xC8, 0xC8, 0xCB, 0xCB, 0xCD, 0xCD, 0xCE, 0xCE, - 0xD0, 0xD0, 0xD3, 0xD3, 0xD5, 0xD5, 0xD6, 0xD6, - 0xD9, 0xD9, 0xDA, 0xDA, 0xDC, 0xDC, 0xDF, 0xDF, - 0xE0, 0xE0, 0xE3, 0xE3, 0xE5, 0xE5, 0xE6, 0xE6, - 0xE9, 0xE9, 0xEA, 0xEA, 0xEC, 0xEC, 0xEF, 0xEF, - 0xF1, 0xF1, 0xF2, 0xF2, 0xF4, 0xF4, 0xF7, 0xF7, - 0xF8, 0xF8, 0xFB, 0xFB, 0xFD, 0xFD, 0xFE, 0xFE - }; - - if (modeCW == 0x03) - { - create_data_cw_mode_03(seed, lenSeed, baseCw, val, ecmBody, data); - create_hash_mode_03(data, hash); - - cw[0] = hash[0x09]; - cw[1] = hash[0x01]; - cw[2] = hash[0x0F]; - cw[3] = hash[0x0E]; - cw[4] = hash[0x04]; - cw[5] = hash[0x02]; - cw[6] = hash[0x05]; - cw[7] = hash[0x0D]; - } - else if (modeCW == 0x04) - { - create_data_cw_mode_04(seed, lenSeed, baseCw, val, ecmBody, data); - create_hash_mode_04(data, hash); - - cw[0] = hash[0x08]; - cw[1] = hash[0x0F]; - cw[2] = hash[0x02]; - cw[3] = hash[0x0A]; - cw[4] = hash[0x06]; - cw[5] = hash[0x03]; - cw[6] = hash[0x09]; - cw[7] = hash[0x0D]; - } - else - { - lenData = create_data_cw(seed, lenSeed, baseCw, val, seedEcmCw, data); - create_hash(data, lenData, hash, hashMode); - - for (i = 0; i < 8; i++) - { - cw[i] = hash[i]; - } - } - - if (modeDesCsa == 0) // DES - Fix Parity Bits - { - for (i = 0; i < 8; i++) - { - cw[i] = tableFixParity[cw[i]]; - } - } - else if (modeDesCsa == 1) // CSA - Fix Checksums - { - cw[3] = cw[0] + cw[1] + cw[2]; - cw[7] = cw[4] + cw[5] + cw[6]; - } -} - -static uint32_t create_channel_hash(uint16_t caid, uint16_t tsid, uint16_t onid, uint32_t ens) -{ - uint8_t buffer[8]; - uint32_t channel_hash = 0; - - if (ens) - { - i2b_buf(2, tsid, buffer); - i2b_buf(2, onid, buffer + 2); - i2b_buf(4, ens, buffer + 4); - - channel_hash = crc32(caid, buffer, sizeof(buffer)); - } - - return channel_hash; -} - -static uint16_t get_channel_group(uint32_t channel_hash) -{ - uint8_t tmp[2]; - uint16_t group = 0; - - if (channel_hash && emu_find_key('P', channel_hash, 0x00000000, "GROUP", tmp, 2, 0, 0, 0, NULL)) - { - group = b2i(2, tmp); - } - - return group; -} - -static inline int8_t get_ecm_key(uint8_t *key, uint32_t provider, uint32_t ignore_mask, uint8_t keyIndex, uint32_t keyRef) -{ - return emu_find_key('P', provider, ignore_mask, keyIndex == 1 ? "01" : "00", key, 7, 0, keyRef, 0, NULL); -} - -static inline int8_t get_emm_key(uint8_t *key, char *uniqueAddress, uint32_t keyRef, uint32_t *groupId) -{ - return emu_find_key('P', 0, 0xFFFFFFFF, uniqueAddress, key, 7, 0, keyRef, 0, groupId); -} - -static const uint8_t PowerVu_A0_S_1[16] = -{ - 0x33, 0xA4, 0x44, 0x3C, 0xCA, 0x2E, 0x75, 0x7B, - 0xBC, 0xE6, 0xE5, 0x35, 0xA0, 0x55, 0xC9, 0xA2 -}; - -static const uint8_t PowerVu_A0_S_2[16] = -{ - 0x5A, 0xB0, 0x2C, 0xBC, 0xDA, 0x32, 0xE6, 0x92, - 0x40, 0x53, 0x6E, 0xF9, 0x69, 0x11, 0x1E, 0xFB -}; - -static const uint8_t PowerVu_A0_S_3[16] = -{ - 0x4E, 0x18, 0x9B, 0x19, 0x79, 0xFB, 0x01, 0xFA, - 0xE3, 0xE1, 0x28, 0x3D, 0x32, 0xE4, 0x92, 0xEA -}; - -static const uint8_t PowerVu_A0_S_4[16] = -{ - 0x05, 0x6F, 0x37, 0x66, 0x35, 0xE1, 0x58, 0xD0, - 0xB4, 0x6A, 0x97, 0xAE, 0xD8, 0x91, 0x27, 0x56 -}; - -static const uint8_t PowerVu_A0_S_5[16] = -{ - 0x7B, 0x26, 0xAD, 0x34, 0x3D, 0x77, 0x39, 0x51, - 0xE0, 0xE0, 0x48, 0x8C, 0x39, 0xF5, 0xE8, 0x47 -}; - -static const uint8_t PowerVu_A0_S_6[16] = -{ - 0x74, 0xFA, 0x4D, 0x79, 0x42, 0x39, 0xD1, 0xA4, - 0x99, 0xA3, 0x97, 0x07, 0xDF, 0x14, 0x3A, 0xC4 -}; - -static const uint8_t PowerVu_A0_S_7[16] = -{ - 0xC6, 0x1E, 0x3C, 0x24, 0x11, 0x08, 0x5D, 0x6A, - 0xEB, 0x97, 0xB9, 0x25, 0xA7, 0xFA, 0xE9, 0x1A -}; - -static const uint8_t PowerVu_A0_S_8[16] = -{ - 0x9A, 0xAD, 0x72, 0xD7, 0x7C, 0x68, 0x3B, 0x55, - 0x1D, 0x4A, 0xA2, 0xB0, 0x38, 0xB9, 0x56, 0xD0 -}; - -static const uint8_t PowerVu_A0_S_9[32] = -{ - 0x61, 0xDA, 0x5F, 0xB7, 0xEB, 0xC6, 0x3F, 0x6C, - 0x09, 0xF3, 0x64, 0x38, 0x33, 0x08, 0xAA, 0x15, - 0xCC, 0xEF, 0x22, 0x64, 0x01, 0x2C, 0x12, 0xDE, - 0xF4, 0x6E, 0x3C, 0xCD, 0x1A, 0x64, 0x63, 0x7C -}; - -static const uint8_t PowerVu_00_S_1[16] = -{ - 0x97, 0x13, 0xEB, 0x6B, 0x04, 0x5E, 0x60, 0x3A, - 0xD9, 0xCC, 0x91, 0xC2, 0x5A, 0xFD, 0xBA, 0x0C -}; - -static const uint8_t PowerVu_00_S_2[16] = -{ - 0x61, 0x3C, 0x03, 0xB0, 0xB5, 0x6F, 0xF8, 0x01, - 0xED, 0xE0, 0xE5, 0xF3, 0x78, 0x0F, 0x0A, 0x73 -}; - -static const uint8_t PowerVu_00_S_3[16] = -{ - 0xFD, 0xDF, 0xD2, 0x97, 0x06, 0x14, 0x91, 0xB5, - 0x36, 0xAD, 0xBC, 0xE1, 0xB3, 0x00, 0x66, 0x41 -}; - -static const uint8_t PowerVu_00_S_4[16] = -{ - 0x8B, 0xD9, 0x18, 0x0A, 0xED, 0xEE, 0x61, 0x34, - 0x1A, 0x79, 0x80, 0x8C, 0x1E, 0x7F, 0xC5, 0x9F -}; - -static const uint8_t PowerVu_00_S_5[16] = -{ - 0xB0, 0xA1, 0xF2, 0xB8, 0xEA, 0x72, 0xDD, 0xD3, - 0x30, 0x65, 0x2B, 0x1E, 0xE9, 0xE1, 0x45, 0x29 -}; - -static const uint8_t PowerVu_00_S_6[16] = -{ - 0x5D, 0xCA, 0x53, 0x75, 0xB2, 0x24, 0xCE, 0xAF, - 0x21, 0x54, 0x9E, 0xBE, 0x02, 0xA9, 0x4C, 0x5D -}; - -static const uint8_t PowerVu_00_S_7[16] = -{ - 0x42, 0x66, 0x72, 0x83, 0x1B, 0x2D, 0x22, 0xC9, - 0xF8, 0x4D, 0xBA, 0xCD, 0xBB, 0x20, 0xBD, 0x6B -}; - -static const uint8_t PowerVu_00_S_8[16] = -{ - 0xC4, 0x0C, 0x6B, 0xD3, 0x6D, 0x94, 0x7E, 0x53, - 0xCE, 0x96, 0xAC, 0x40, 0x2C, 0x7A, 0xD3, 0xA9 -}; - -static const uint8_t PowerVu_00_S_9[32] = -{ - 0x31, 0x82, 0x4F, 0x9B, 0xCB, 0x6F, 0x9D, 0xB7, - 0xAE, 0x68, 0x0B, 0xA0, 0x93, 0x15, 0x32, 0xE2, - 0xED, 0xE9, 0x47, 0x29, 0xC2, 0xA8, 0x92, 0xEF, - 0xBA, 0x27, 0x22, 0x57, 0x76, 0x54, 0xC0, 0x59 -}; - -static uint8_t powervu_sbox(uint8_t *input, uint8_t mode) -{ - uint8_t s_index, bit, last_index, last_bit; - uint8_t const *Sbox1, *Sbox2, *Sbox3, *Sbox4, *Sbox5, *Sbox6, *Sbox7, *Sbox8, *Sbox9; - - if (mode) - { - Sbox1 = PowerVu_A0_S_1; - Sbox2 = PowerVu_A0_S_2; - Sbox3 = PowerVu_A0_S_3; - Sbox4 = PowerVu_A0_S_4; - Sbox5 = PowerVu_A0_S_5; - Sbox6 = PowerVu_A0_S_6; - Sbox7 = PowerVu_A0_S_7; - Sbox8 = PowerVu_A0_S_8; - Sbox9 = PowerVu_A0_S_9; - } - else - { - Sbox1 = PowerVu_00_S_1; - Sbox2 = PowerVu_00_S_2; - Sbox3 = PowerVu_00_S_3; - Sbox4 = PowerVu_00_S_4; - Sbox5 = PowerVu_00_S_5; - Sbox6 = PowerVu_00_S_6; - Sbox7 = PowerVu_00_S_7; - Sbox8 = PowerVu_00_S_8; - Sbox9 = PowerVu_00_S_9; - } - - bit = (get_bit(input[2], 0) << 2) | (get_bit(input[3], 4) << 1) | (get_bit(input[5], 3)); - s_index = (get_bit(input[0], 0) << 3) | (get_bit(input[2], 6) << 2) | (get_bit(input[2], 4) << 1) | (get_bit(input[5], 7)); - last_bit = get_bit(Sbox1[s_index], 7 - bit); - - bit = (get_bit(input[5], 0) << 2) | (get_bit(input[4], 0) << 1) | (get_bit(input[6], 2)); - s_index = (get_bit(input[2], 1) << 3) | (get_bit(input[2], 2) << 2) | (get_bit(input[5], 5) << 1) | (get_bit(input[5], 1)); - last_bit = last_bit | (get_bit(Sbox2[s_index], 7 - bit) << 1); - - bit = (get_bit(input[6], 0) << 2) | (get_bit(input[1], 7) << 1) | (get_bit(input[6], 7)); - s_index = (get_bit(input[1], 3) << 3) | (get_bit(input[3], 7) << 2) | (get_bit(input[1], 5) << 1) | (get_bit(input[5], 2)); - last_bit = last_bit | (get_bit(Sbox3[s_index], 7 - bit) << 2); - - bit = (get_bit(input[1], 0) << 2) | (get_bit(input[2], 7) << 1) | (get_bit(input[2], 5)); - s_index = (get_bit(input[6], 3) << 3) | (get_bit(input[6], 4) << 2) | (get_bit(input[6], 6) << 1) | (get_bit(input[3], 5)); - last_index = get_bit(Sbox4[s_index], 7 - bit); - - bit = (get_bit(input[3], 3) << 2) | (get_bit(input[4], 6) << 1) | (get_bit(input[3], 2)); - s_index = (get_bit(input[3], 1) << 3) | (get_bit(input[4], 5) << 2) | (get_bit(input[3], 0) << 1) | (get_bit(input[4], 7)); - last_index = last_index | (get_bit(Sbox5[s_index], 7 - bit) << 1); - - bit = (get_bit(input[5], 4) << 2) | (get_bit(input[4], 4) << 1) | (get_bit(input[1], 2)); - s_index = (get_bit(input[2], 3) << 3) | (get_bit(input[6], 5) << 2) | (get_bit(input[1], 4) << 1) | (get_bit(input[4], 1)); - last_index = last_index | (get_bit(Sbox6[s_index], 7 - bit) << 2); - - bit = (get_bit(input[0], 6) << 2) | (get_bit(input[0], 7) << 1) | (get_bit(input[0], 4)); - s_index = (get_bit(input[0], 5) << 3) | (get_bit(input[0], 3) << 2) | (get_bit(input[0], 1) << 1) | (get_bit(input[0], 2)); - last_index = last_index | (get_bit(Sbox7[s_index], 7 - bit) << 3); - - bit = (get_bit(input[4], 2) << 2) | (get_bit(input[4], 3) << 1) | (get_bit(input[1], 1)); - s_index = (get_bit(input[1], 6) << 3) | (get_bit(input[6], 1) << 2) | (get_bit(input[5], 6) << 1) | (get_bit(input[3], 6)); - last_index = last_index | (get_bit(Sbox8[s_index], 7 - bit) << 4); - - return (get_bit(Sbox9[last_index & 0x1F], 7 - last_bit) & 1) ? 1 : 0; -} - -static void powervu_decrypt(uint8_t *data, uint32_t length, uint8_t *key, uint8_t sbox) -{ - uint32_t i; - int32_t j, k; - uint8_t curByte, tmpBit; - - for (i = 0; i < length; i++) - { - curByte = data[i]; - - for (j = 7; j >= 0; j--) - { - data[i] = set_bit(data[i], j, (get_bit(curByte, j) ^ powervu_sbox(key, sbox)) ^ get_bit(key[0], 7)); - tmpBit = get_bit(data[i], j) ^ (get_bit(key[6], 0)); - - if (tmpBit) - { - key[3] ^= 0x10; - } - - for (k = 6; k > 0; k--) - { - key[k] = (key[k] >> 1) | (key[k - 1] << 7); - } - - key[0] = (key[0] >> 1); - key[0] = set_bit(key[0], 7, tmpBit); - } - } -} - -static void expand_des_key(unsigned char *key) -{ - uint8_t i, j, parity; - uint8_t tmpKey[7]; - - memcpy(tmpKey, key, 7); - - key[0] = (tmpKey[0] & 0xFE); - key[1] = ((tmpKey[0] << 7) | ((tmpKey[1] >> 1) & 0xFE)); - key[2] = ((tmpKey[1] << 6) | ((tmpKey[2] >> 2) & 0xFE)); - key[3] = ((tmpKey[2] << 5) | ((tmpKey[3] >> 3) & 0xFE)); - key[4] = ((tmpKey[3] << 4) | ((tmpKey[4] >> 4) & 0xFE)); - key[5] = ((tmpKey[4] << 3) | ((tmpKey[5] >> 5) & 0xFE)); - key[6] = ((tmpKey[5] << 2) | ((tmpKey[6] >> 6) & 0xFE)); - key[7] = (tmpKey[6] << 1); - - for (i = 0; i < 8; i++) - { - parity = 1; - - for (j = 1; j < 8; j++) - { - if ((key[i] >> j) & 0x1) - { - parity = ~parity & 0x01; - } - } - - key[i] |= parity; - } -} - -static uint8_t get_conv_cw_index(uint8_t ecmTag) -{ - switch (ecmTag) - { - case PVU_CONVCW_VID_ECM: - return PVU_CW_VID; - - case PVU_CONVCW_HSD_ECM: - return PVU_CW_HSD; - - case PVU_CONVCW_A1_ECM: - return PVU_CW_A1; - - case PVU_CONVCW_A2_ECM: - return PVU_CW_A2; - - case PVU_CONVCW_A3_ECM: - return PVU_CW_A3; - - case PVU_CONVCW_A4_ECM: - return PVU_CW_A4; - - case PVU_CONVCW_UTL_ECM: - return PVU_CW_UTL; - - case PVU_CONVCW_VBI_ECM: - return PVU_CW_VBI; - - default: - return PVU_CW_VBI; - } -} - -static uint16_t get_seed_iv(uint8_t seedType, uint8_t *ecm) -{ - switch (seedType) - { - case PVU_CW_VID: - return ((ecm[0x10] & 0x1F) << 3) | 0; - - case PVU_CW_HSD: - return ((ecm[0x12] & 0x1F) << 3) | 2; - - case PVU_CW_A1: - return ((ecm[0x11] & 0x3F) << 3) | 1; - - case PVU_CW_A2: - return ((ecm[0x13] & 0x3F) << 3) | 1; - - case PVU_CW_A3: - return ((ecm[0x19] & 0x3F) << 3) | 1; - - case PVU_CW_A4: - return ((ecm[0x1A] & 0x3F) << 3) | 1; - - case PVU_CW_UTL: - return ((ecm[0x14] & 0x0F) << 3) | 4; - - case PVU_CW_VBI: - return (((ecm[0x15] & 0xF8) >> 3) << 3) | 5; - - default: - return 0; - } -} - -static uint8_t expand_seed(uint8_t seedType, uint8_t *seed) -{ - uint8_t seedLength = 0, i; - - switch (seedType) - { - case PVU_CW_VID: - case PVU_CW_HSD: - seedLength = 4; - break; - - case PVU_CW_A1: - case PVU_CW_A2: - case PVU_CW_A3: - case PVU_CW_A4: - seedLength = 3; - break; - - case PVU_CW_UTL: - case PVU_CW_VBI: - seedLength = 2; - break; - - default: - return seedLength; - } - - for (i = seedLength; i < 7; i++) - { - seed[i] = seed[i % seedLength]; - } - - return seedLength; -} - -static void calculate_seed(uint8_t seedType, uint8_t *ecm, uint8_t *seedBase, - uint8_t *key, uint8_t *seed, uint8_t sbox) -{ - uint16_t tmpSeed; - - tmpSeed = get_seed_iv(seedType, ecm + 23); - - seed[0] = (tmpSeed >> 2) & 0xFF; - seed[1] = ((tmpSeed & 0x3) << 6) | (seedBase[0] >> 2); - seed[2] = ( seedBase[0] << 6) | (seedBase[1] >> 2); - seed[3] = ( seedBase[1] << 6) | (seedBase[2] >> 2); - seed[4] = ( seedBase[2] << 6) | (seedBase[3] >> 2); - seed[5] = ( seedBase[3] << 6); - - powervu_decrypt(seed, 6, key, sbox); - - seed[0] = (seed[1] << 2) | (seed[2] >> 6); - seed[1] = (seed[2] << 2) | (seed[3] >> 6); - seed[2] = (seed[3] << 2) | (seed[4] >> 6); - seed[3] = (seed[4] << 2) | (seed[5] >> 6); -} - -static void calculate_cw(uint8_t seedType, uint8_t *seed, uint8_t csaUsed, uint8_t *convolvedCw, - uint8_t *cw, uint8_t *baseCw, uint8_t *seedEcmCw, uint8_t hashModeCw, - uint8_t needsUnmasking, uint8_t xorMode, int modeCW, uint8_t* ecmBody) -{ - int32_t k; - uint8_t seedLength, val = 0; - - seedLength = expand_seed(seedType, seed); - - if (needsUnmasking && (((modeCW >= 0x00) && (hashModeCw > 0) && (hashModeCw <= 0x27) && - (hashModeCw != 0x0B) && (hashModeCw != 0x0C) && (hashModeCw != 0x0D) && (hashModeCw != 0x0E)) || - (modeCW == 0x03) || (modeCW == 0x04))) - { - switch (seedType) - { - case PVU_CW_VID: - val = 0; - break; - - case PVU_CW_A1: - case PVU_CW_A2: - case PVU_CW_A3: - case PVU_CW_A4: - val = 1; - break; - - case PVU_CW_HSD: - val = 2; - break; - - case PVU_CW_UTL: - val = 4; - break; - - case PVU_CW_VBI: - val = 5; - break; - } - - create_cw(seed, seedLength, baseCw, val, seedEcmCw, cw, csaUsed, hashModeCw, modeCW, ecmBody); - - if (csaUsed) - { - cw[0] = cw[0] ^ convolvedCw[0]; - cw[1] = cw[1] ^ convolvedCw[1]; - cw[2] = cw[2] ^ convolvedCw[2]; - cw[3] = cw[3] ^ convolvedCw[3]; - cw[4] = cw[4] ^ convolvedCw[4]; - cw[5] = cw[5] ^ convolvedCw[5]; - cw[6] = cw[6] ^ convolvedCw[6]; - cw[7] = cw[7] ^ convolvedCw[7]; - - cw[3] = cw[0] + cw[1] + cw[2]; - cw[7] = cw[4] + cw[5] + cw[6]; - } - } - else - { - if (csaUsed) - { - for (k = 0; k < 7; k++) - { - seed[k] ^= baseCw[k]; - } - - cw[0] = seed[0] ^ convolvedCw[0]; - cw[1] = seed[1] ^ convolvedCw[1]; - cw[2] = seed[2] ^ convolvedCw[2]; - cw[3] = seed[3] ^ convolvedCw[3]; - cw[4] = seed[3] ^ convolvedCw[4]; - cw[5] = seed[4] ^ convolvedCw[5]; - cw[6] = seed[5] ^ convolvedCw[6]; - cw[7] = seed[6] ^ convolvedCw[7]; - } - else - { - if (xorMode == 0) - { - for (k = 0; k < 7; k++) - { - cw[k] = seed[k] ^ baseCw[k]; - } - } - - if (xorMode == 1) - { - for (k = 0; k < 3; k++) - { - cw[k] = seed[k] ^ baseCw[k]; - } - - for (k = 3; k < 7; k++) - { - cw[k] = baseCw[k]; - } - } - - expand_des_key(cw); - } - } -} - -#ifdef MODULE_STREAMRELAY -int8_t powervu_ecm(uint8_t *ecm, uint8_t *dw, EXTENDED_CW *cw_ex, uint16_t srvid, uint16_t caid, uint16_t tsid, uint16_t onid, uint32_t ens, emu_stream_client_key_data *cdata) -#else -int8_t powervu_ecm(uint8_t *ecm, uint8_t *dw, EXTENDED_CW *cw_ex, uint16_t srvid, uint16_t caid, uint16_t tsid, uint16_t onid, uint32_t ens) -#endif -{ - uint32_t i, j, k; - uint32_t ecmCrc32, keyRef0, keyRef1, keyRef2, channel_hash, group_id = 0; - - uint16_t ecmLen = SCT_LEN(ecm); - uint16_t nanoLen, channelId, ecmSrvid; - - uint8_t keyIndex, sbox, decrypt_ok, calculateAll, hashModeCw = 0, needsUnmasking, xorMode; - uint8_t nanoCmd, nanoChecksum, keyType, fixedKey, oddKey, bid, csaUsed, modeCW = 0, offsetBody; - - uint8_t ecmKey[7], tmpEcmKey[7], seedBase[4], baseCw[7], seed[8][8], cw[8][8], convolvedCw[8][8]; - uint8_t ecmPart1[14], ecmPart2[27], unmaskedEcm[ecmLen], seedEcmCw[16]; - - //char tmpBuffer1[512]; - char tmpBuffer2[17]; - -#ifdef MODULE_STREAMRELAY - emu_stream_cw_item *cw_item; - int8_t update_global_key = 0; - int8_t update_global_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS]; - - memset(update_global_keys, 0, sizeof(update_global_keys)); -#else -#define EMU_STREAM_MAX_AUDIO_SUB_TRACKS 4 -#endif - - if (ecmLen < 7) - { - return EMU_NOT_SUPPORTED; - } - - needsUnmasking = (ecm[3] & 0xF0) == 0x50; - - //cs_log_dbg(D_ATR, "ecm1: %s", cs_hexdump(0, ecm, ecmLen, tmpBuffer1, sizeof(tmpBuffer1))); - - if (needsUnmasking) - { - hashModeCw = unmask_ecm(ecm, seedEcmCw, &modeCW); - } - - //cs_log_dbg(D_ATR, "needsUnmasking=%d", needsUnmasking); - //cs_log_dbg(D_ATR, "ecm2: %s", cs_hexdump(0, ecm, ecmLen, tmpBuffer1, sizeof(tmpBuffer1))); - - memcpy(unmaskedEcm, ecm, ecmLen); - - ecmCrc32 = b2i(4, ecm + ecmLen - 4); - - if (ccitt32_crc(ecm, ecmLen - 4) != ecmCrc32) - { - return EMU_CHECKSUM_ERROR; - } - ecmLen -= 4; - - for (i = 0; i < 8; i++) - { - memset(convolvedCw[i], 0, 8); - } - - for (i = 3; i + 3 < ecmLen; ) - { - nanoLen = (((ecm[i] & 0x0F) << 8) | ecm[i + 1]); - i += 2; - - if (nanoLen > 0) - { - nanoLen--; - } - nanoCmd = ecm[i++]; - - if (i + nanoLen > ecmLen) - { - return EMU_NOT_SUPPORTED; - } - - switch (nanoCmd) - { - case 0x27: - if (nanoLen < 15) - { - break; - } - - nanoChecksum = 0; - for (j = 4; j < 15; j++) - { - nanoChecksum += ecm[i + j]; - } - - if (nanoChecksum != 0) - { - break; - } - - keyType = get_conv_cw_index(ecm[i + 4]); - memcpy(convolvedCw[keyType], &ecm[i + 6], 8); - break; - - default: - break; - } - - i += nanoLen; - } - - for (i = 3; i + 3 < ecmLen; ) - { - nanoLen = (((ecm[i] & 0x0F) << 8) | ecm[i + 1]); - i += 2; - - if (nanoLen > 0) - { - nanoLen--; - } - nanoCmd = ecm[i++]; - - if (i + nanoLen > ecmLen) - { - return EMU_NOT_SUPPORTED; - } - - switch (nanoCmd) - { - case 0x20: - { - if (nanoLen < 54) - { - break; - } - - offsetBody = i + 4 + ecm[i + 3]; - i += ecm[i + 3]; // Extra Data Length - - csaUsed = get_bit(ecm[i + 7], 7); - fixedKey = !get_bit(ecm[i + 6], 5); - oddKey = get_bit(ecm[i + 6], 4); - xorMode = get_bit(ecm[i + 6], 0); - bid = (get_bit(ecm[i + 7], 1) << 1) | get_bit(ecm[i + 7], 0); - sbox = get_bit(ecm[i + 6], 3); - - keyIndex = (fixedKey << 3) | (bid << 2) | oddKey; - channelId = b2i(2, ecm + i + 23); - ecmSrvid = (channelId >> 4) | ((channelId & 0xF) << 12); - - cs_log_dbg(D_ATR, "csaUsed: %d, xorMode: %d, ecmSrvid: %04X (%d), hashModeCw: %d, modeCW: %d", - csaUsed, xorMode, ecmSrvid, srvid, hashModeCw, modeCW); - - channel_hash = create_channel_hash(caid, tsid, onid, ens); - group_id = get_channel_group(channel_hash); - - cs_log_dbg(D_ATR, "channel hash: %08X, group id: %04X", channel_hash, group_id); - - decrypt_ok = 0; - - memcpy(ecmPart1, ecm + i + 8, 14); - memcpy(ecmPart2, ecm + i + 27, 27); - - keyRef0 = 0; - keyRef1 = 0; - keyRef2 = 0; - - do - { - if (!group_id || !get_ecm_key(ecmKey, group_id << 16, 0x0000FFFF, keyIndex, keyRef0++)) - { - if (!get_ecm_key(ecmKey, ecmSrvid, 0xFFFF0000, keyIndex, keyRef1++)) - { - if (!get_ecm_key(ecmKey, channelId, 0xFFFF0000, keyIndex, keyRef2++)) - { - cs_log("Key not found or invalid: P ****%04X %02X", ecmSrvid, keyIndex); - - if (group_id) // Print only if there is a matching "GROUP" entry - { - cs_log("Key not found or invalid: P %04XFFFF %02X", group_id, keyIndex); - } - - return EMU_KEY_NOT_FOUND; - } - } - } - - powervu_decrypt(ecm + i + 8, 14, ecmKey, sbox); - - if ((ecm[i + 6] != ecm[i + 6 + 7]) || (ecm[i + 6 + 8] != ecm[i + 6 + 15])) - { - memcpy(ecm + i + 8, ecmPart1, 14); - continue; - } - - memcpy(tmpEcmKey, ecmKey, 7); - - powervu_decrypt(ecm + i + 27, 27, ecmKey, sbox); - - if ((ecm[i + 23] != ecm[i + 23 + 29]) || (ecm[i + 23 + 1] != ecm[i + 23 + 30])) - { - memcpy(ecm + i + 8, ecmPart1, 14); - memcpy(ecm + i + 27, ecmPart2, 27); - continue; - } - - decrypt_ok = 1; - } - while (!decrypt_ok); - - memcpy(seedBase, ecm + i + 6 + 2, 4); - -#ifdef MODULE_STREAMRELAY - if (cdata == NULL) - { - SAFE_MUTEX_LOCK(&emu_fixed_key_srvid_mutex); - for (j = 0; j < EMU_STREAM_SERVER_MAX_CONNECTIONS; j++) - { - if (!stream_server_has_ecm[j] && emu_stream_cur_srvid[j] == srvid) - { - update_global_key = 1; - update_global_keys[j] = 1; - } - } - SAFE_MUTEX_UNLOCK(&emu_fixed_key_srvid_mutex); - } - - calculateAll = cdata != NULL || update_global_key || cw_ex != NULL; -#else - calculateAll = cw_ex != NULL; -#endif - - if (calculateAll) // Calculate all seeds - { - for (j = 0; j < 8; j++) - { - memcpy(ecmKey, tmpEcmKey, 7); - calculate_seed(j, ecm + i, seedBase, ecmKey, seed[j], sbox); - } - } - else // Calculate only video seed - { - memcpy(ecmKey, tmpEcmKey, 7); - calculate_seed(PVU_CW_VID, ecm + i, seedBase, ecmKey, seed[PVU_CW_VID], sbox); - } - - memcpy(baseCw, ecm + i + 6 + 8, 7); - - if (calculateAll) // Calculate all CWs - { - for (j = 0; j < 8; j++) - { - calculate_cw(j, seed[j], csaUsed, convolvedCw[j], cw[j], baseCw, seedEcmCw, - hashModeCw, needsUnmasking, xorMode, modeCW, unmaskedEcm + offsetBody); - - if (csaUsed) - { - for (k = 0; k < 8; k += 4) - { - cw[j][k + 3] = ((cw[j][k] + cw[j][k + 1] + cw[j][k + 2]) & 0xFF); - } - } - - cs_log_dbg(D_ATR, "calculated cw %d: %s", j, - cs_hexdump(0, cw[j], 8, tmpBuffer2, sizeof(tmpBuffer2))); - } - - //cs_log_dbg(D_ATR, "csaUsed=%d, cw: %s cdata=%x, cw_ex=%x", - // csaUsed, cs_hexdump(3, cw[0], 8, tmpBuffer1, sizeof(tmpBuffer1)), - // (unsigned int)cdata, (unsigned int)cw_ex); - -#ifdef MODULE_STREAMRELAY - if (update_global_key) - { - for (j = 0; j < EMU_STREAM_SERVER_MAX_CONNECTIONS; j++) - { - if (update_global_keys[j]) - { - cw_item = (emu_stream_cw_item *)malloc(sizeof(emu_stream_cw_item)); - if (cw_item != NULL) - { - cw_item->csa_used = csaUsed; - cw_item->is_even = ecm[0] == 0x80 ? 1 : 0; - cs_ftime(&cw_item->write_time); - add_ms_to_timeb(&cw_item->write_time, cfg.emu_stream_ecm_delay); - memcpy(cw_item->cw, cw, sizeof(cw)); - ll_append(ll_emu_stream_delayed_keys[j], cw_item); - } - } - } - } - - if (cdata != NULL) - { - for (j = 0; j < EMU_STREAM_MAX_AUDIO_SUB_TRACKS + 2; j++) - { - if (csaUsed) - { - if (ecm[0] == 0x80) - { - if (has_dvbcsa_ecm) - { - dvbcsa_bs_key_set(cw[j], key_data[cdata->connid].key[j][EVEN]); - } - } - else - { - if (has_dvbcsa_ecm) - { - dvbcsa_bs_key_set(cw[j], key_data[cdata->connid].key[j][ODD]); - } - } - - cdata->csa_used = 1; - } - else - { - if (ecm[0] == 0x80) - { - des_set_key(cw[j], cdata->pvu_des_ks[j][0]); - } - else - { - des_set_key(cw[j], cdata->pvu_des_ks[j][1]); - } - - cdata->csa_used = 0; - } - } - } -#endif - - if (cw_ex != NULL) - { - cw_ex->mode = CW_MODE_MULTIPLE_CW; - - if (csaUsed) - { - cw_ex->algo = CW_ALGO_CSA; - cw_ex->algo_mode = CW_ALGO_MODE_CBC; - } - else - { - cw_ex->algo = CW_ALGO_DES; - cw_ex->algo_mode = CW_ALGO_MODE_ECB; - } - - for (j = 0; j < EMU_STREAM_MAX_AUDIO_SUB_TRACKS; j++) - { - memset(cw_ex->audio[j], 0, 16); - - if (ecm[0] == 0x80) - { - memcpy(cw_ex->audio[j], cw[PVU_CW_A1 + j], 8); - } - else - { - memcpy(&cw_ex->audio[j][8], cw[PVU_CW_A1 + j], 8); - } - } - - memset(cw_ex->data, 0, 16); - - if (ecm[0] == 0x80) - { - memcpy(cw_ex->data, cw[PVU_CW_HSD], 8); - } - else - { - memcpy(&cw_ex->data[8], cw[PVU_CW_HSD], 8); - } - } - } - else // Calculate only video CW - { - calculate_cw(PVU_CW_VID, seed[PVU_CW_VID], csaUsed, convolvedCw[PVU_CW_VID], - cw[PVU_CW_VID], baseCw, seedEcmCw, hashModeCw, needsUnmasking, - xorMode, modeCW, unmaskedEcm + offsetBody); - - if (csaUsed) - { - for (k = 0; k < 8; k += 4) - { - cw[PVU_CW_VID][k + 3] = ((cw[PVU_CW_VID][k] + cw[PVU_CW_VID][k + 1] + cw[PVU_CW_VID][k + 2]) & 0xFF); - } - } - - cs_log_dbg(D_ATR, "calculated video only cw: %s", - cs_hexdump(0, cw[PVU_CW_VID], 8, tmpBuffer2, sizeof(tmpBuffer2))); - } - - memset(dw, 0, 16); - - if (ecm[0] == 0x80) - { - memcpy(dw, cw[PVU_CW_VID], 8); - } - else - { - memcpy(&dw[8], cw[PVU_CW_VID], 8); - } - - return EMU_OK; - } - - default: - break; - } - - i += nanoLen; - } - - return EMU_NOT_SUPPORTED; -} - -// PowerVu EMM EMU -static void create_data_unmask_emm_mode_03(uint8_t *emmBody, uint8_t *data) -{ - int i; - uint8_t padding[] = - { - 0xB3, 0x60, 0x35, 0xC8, 0x5C, 0x26, 0xC1, 0xD0, - 0x88, 0x86, 0x57, 0xB6, 0x45, 0xA7, 0xDF, 0x7E, - 0xF0, 0xA8, 0x49, 0xFB, 0x79, 0x6C, 0xAF, 0xB0 - }; - - memcpy(data + 40, padding, 24); - - for (i = 0; i < 5; i++) - { - data[0 + i * 8] = emmBody[0x18 + i * 0x1B]; - data[1 + i * 8] = emmBody[0x16 + i * 0x1B]; - data[2 + i * 8] = emmBody[0x07 + i * 0x1B]; - data[3 + i * 8] = emmBody[0x0B + i * 0x1B]; - data[4 + i * 8] = emmBody[0x06 + i * 0x1B]; - data[5 + i * 8] = emmBody[0x19 + i * 0x1B]; - data[6 + i * 8] = emmBody[0x15 + i * 0x1B]; - data[7 + i * 8] = emmBody[0x03 + i * 0x1B]; - } -} - -static void create_data_unmask_emm_mode_04(uint8_t *emmBody, uint8_t *data) -{ - int i; - uint8_t padding[] = - { - 0x56, 0xC7, 0x05, 0x66, 0xC7, 0x4E, 0xC1, 0xA0, - 0x9E, 0xD1, 0xFE, 0x92, 0xE8, 0xCD, 0x5F, 0xAF, - 0xCF, 0xE5, 0xE9, 0x9E, 0x7A, 0x38, 0xAC, 0x68 - }; - - memcpy(data + 0x28, padding, 0x18); - - for (i = 0; i < 5; i++) - { - data[0 + i * 8] = emmBody[0x06 + i * 0x1B]; - data[1 + i * 8] = emmBody[0x19 + i * 0x1B]; - data[2 + i * 8] = emmBody[0x16 + i * 0x1B]; - data[3 + i * 8] = emmBody[0x0A + i * 0x1B]; - data[4 + i * 8] = emmBody[0x13 + i * 0x1B]; - data[5 + i * 8] = emmBody[0x05 + i * 0x1B]; - data[6 + i * 8] = emmBody[0x14 + i * 0x1B]; - data[7 + i * 8] = emmBody[0x18 + i * 0x1B]; - } -} - -static uint8_t get_mode_unmask_emm(uint8_t *extraData) -{ - uint16_t data = ((uint16_t)extraData[0] << 8) + extraData[1]; - - if (data == 0) - { - return 0x00; - } - - switch (data & 0x0881) - { - case 0x0080: - case 0x0881: - return 0x01; - - case 0x0001: - case 0x0880: - return 0x02; - - case 0x0800: - case 0x0081: - return 0x03; - - case 0x0000: - case 0x0801: - switch (data & 0x9020) - { - case 0x8000: - case 0x9000: - return 0x04; - - case 0x0020: - case 0x9020: - return 0x05; - - case 0x0000: - case 0x1000: - return 0x06; - - case 0x1020: - case 0x8020: - switch (data & 0x2014) - { - case 0x2004: - case 0x2010: - return 0x07; - - case 0x0000: - case 0x0004: - return 0x08; - - case 0x0014: - case 0x2014: - return 0x09; - - case 0x0010: - case 0x2000: - return 0x00; - } - break; - } - break; - } - return 0x00; -} - -static void unmask_emm(uint8_t *emm) -{ - uint32_t crc, i, l; - uint8_t hashModeEmm, modeUnmask, data[64], mask[16]; - - uint8_t sourcePos[] = - { - 0x03, 0x0C, 0x0D, 0x11, 0x15, 0x18, 0x1D, 0x1F, 0x25, 0x2A, - 0x32, 0x35, 0x3A, 0x3B, 0x3E, 0x42, 0x47, 0x48, 0x53, 0x58, - 0x5C, 0x61, 0x66, 0x69, 0x71, 0x72, 0x78, 0x7B, 0x81, 0x84 - }; - - uint8_t destPos[] = - { - 0x02, 0x08, 0x0B, 0x0E, 0x13, 0x16, 0x1E, 0x23, 0x28, 0x2B, - 0x2F, 0x33, 0x38, 0x3C, 0x40, 0x44, 0x4A, 0x4D, 0x54, 0x57, - 0x5A, 0x63, 0x68, 0x6A, 0x70, 0x75, 0x76, 0x7D, 0x82, 0x85 - }; - - // Create Mask for ECM decryption - create_data_ecm_emm(emm, sourcePos, 19, 30, data); - - hashModeEmm = emm[8] ^ crc8_calc(data, 30); - modeUnmask = get_mode_unmask_emm(emm + 16); - - if ((modeUnmask == 0x00) || (modeUnmask > 4)) - { - create_hash(data, 30, mask, hashModeEmm); - - // Unmask Body - for (i = 0; i < 30; i++) - { - emm[19 + destPos[i]] ^= mask[i & 0x0F]; - } - } - else if (modeUnmask == 0x03) - { - for (i = 0; i < 5; i++) - { - emm[0x13 + 0x03 + i * 0x1B] -= emm[0x13 + 0x0D + i * 0x1B]; - emm[0x13 + 0x06 + i * 0x1B] -= emm[0x13 + 0x1A + i * 0x1B]; - emm[0x13 + 0x07 + i * 0x1B] -= emm[0x13 + 0x10 + i * 0x1B]; - emm[0x13 + 0x0B + i * 0x1B] -= emm[0x13 + 0x17 + i * 0x1B]; - emm[0x13 + 0x15 + i * 0x1B] -= emm[0x13 + 0x05 + i * 0x1B]; - emm[0x13 + 0x16 + i * 0x1B] -= emm[0x13 + 0x0F + i * 0x1B]; - emm[0x13 + 0x18 + i * 0x1B] -= emm[0x13 + 0x14 + i * 0x1B]; - emm[0x13 + 0x19 + i * 0x1B] -= emm[0x13 + 0x04 + i * 0x1B]; - } - - create_data_unmask_emm_mode_03(emm + 0x13, data); - create_hash_mode_03(data, mask); - - for (i = 0; i < 5; i++) - { - emm[0x13 + 0x14 + i * 0x1B] ^= mask[0x00]; - emm[0x13 + 0x0F + i * 0x1B] ^= mask[0x01]; - emm[0x13 + 0x10 + i * 0x1B] ^= mask[0x02]; - emm[0x13 + 0x17 + i * 0x1B] ^= mask[0x03]; - emm[0x13 + 0x1A + i * 0x1B] ^= mask[0x04]; - emm[0x13 + 0x04 + i * 0x1B] ^= mask[0x05]; - emm[0x13 + 0x05 + i * 0x1B] ^= mask[0x06]; - emm[0x13 + 0x0D + i * 0x1B] ^= mask[0x07]; - emm[0x13 + 0x09 + i * 0x1B] ^= mask[0x08]; - emm[0x13 + 0x0A + i * 0x1B] ^= mask[0x09]; - emm[0x13 + 0x0E + i * 0x1B] ^= mask[0x0A]; - emm[0x13 + 0x11 + i * 0x1B] ^= mask[0x0B]; - emm[0x13 + 0x12 + i * 0x1B] ^= mask[0x0C]; - emm[0x13 + 0x13 + i * 0x1B] ^= mask[0x0D]; - emm[0x13 + 0x08 + i * 0x1B] ^= mask[0x0E]; - emm[0x13 + 0x0C + i * 0x1B] ^= mask[0x0F]; - } - } - else if (modeUnmask == 0x04) - { - for (i = 0; i < 5; i++) - { - emm[0x13 + 0x05 + i * 0x1B] -= emm[0x13 + 0x04 + i * 0x1B]; - emm[0x13 + 0x06 + i * 0x1B] -= emm[0x13 + 0x0B + i * 0x1B]; - emm[0x13 + 0x0A + i * 0x1B] -= emm[0x13 + 0x17 + i * 0x1B]; - emm[0x13 + 0x13 + i * 0x1B] -= emm[0x13 + 0x1A + i * 0x1B]; - emm[0x13 + 0x14 + i * 0x1B] -= emm[0x13 + 0x0E + i * 0x1B]; - emm[0x13 + 0x16 + i * 0x1B] -= emm[0x13 + 0x15 + i * 0x1B]; - emm[0x13 + 0x18 + i * 0x1B] -= emm[0x13 + 0x08 + i * 0x1B]; - emm[0x13 + 0x19 + i * 0x1B] -= emm[0x13 + 0x12 + i * 0x1B]; - } - - create_data_unmask_emm_mode_04(emm + 0x13, data); - create_hash_mode_04(data, mask); - - for (i = 0; i < 5; i++) - { - emm[0x13 + 0x0B + i * 0x1B] ^= mask[0x00]; - emm[0x13 + 0x12 + i * 0x1B] ^= mask[0x01]; - emm[0x13 + 0x15 + i * 0x1B] ^= mask[0x02]; - emm[0x13 + 0x17 + i * 0x1B] ^= mask[0x03]; - emm[0x13 + 0x1A + i * 0x1B] ^= mask[0x04]; - emm[0x13 + 0x04 + i * 0x1B] ^= mask[0x05]; - emm[0x13 + 0x0E + i * 0x1B] ^= mask[0x06]; - emm[0x13 + 0x08 + i * 0x1B] ^= mask[0x07]; - emm[0x13 + 0x09 + i * 0x1B] ^= mask[0x08]; - emm[0x13 + 0x0C + i * 0x1B] ^= mask[0x09]; - emm[0x13 + 0x03 + i * 0x1B] ^= mask[0x0A]; - emm[0x13 + 0x0F + i * 0x1B] ^= mask[0x0B]; - emm[0x13 + 0x10 + i * 0x1B] ^= mask[0x0C]; - emm[0x13 + 0x07 + i * 0x1B] ^= mask[0x0D]; - emm[0x13 + 0x0D + i * 0x1B] ^= mask[0x0E]; - emm[0x13 + 0x11 + i * 0x1B] ^= mask[0x0F]; - } - } - else - { - cs_log("A new unknown emm mode [%d] is in use.", modeUnmask); - } - - // Fix Header - emm[3] &= 0x0F; - emm[3] |= 0x10; - emm[8] = 0x00; - - // Fix CRC (optional) - l = (((emm[1] << 8) + emm[2]) & 0xFFF) + 3 - 4; - crc = ccitt32_crc(emm, l); - - emm[l + 0] = crc >> 24; - emm[l + 1] = crc >> 16; - emm[l + 2] = crc >> 8; - emm[l + 3] = crc >> 0; -} - -static int8_t update_ecm_keys_by_group(uint32_t groupId, uint8_t keyIndex, uint8_t *Key, uint32_t uniqueAddress) -{ - int8_t ret = 0; - uint8_t oldKey[7]; - uint32_t foundProvider = 0, keyRef = 0; - char indexStr[3], uaInfo[13]; - - snprintf(indexStr, 3, "%02X", keyIndex); - snprintf(uaInfo, 13, "UA: %08X", uniqueAddress); - - SAFE_MUTEX_LOCK(&emu_key_data_mutex); - while (emu_find_key('P', groupId << 16 & 0xFFFF0000, 0x0000FFFF, indexStr, oldKey, 7, 0, keyRef, 0, &foundProvider)) - { - keyRef++; - - if (memcmp(oldKey, Key, 7) == 0) // New ECM key already in the db - { - continue; - } - - if (emu_set_key('P', foundProvider, indexStr, Key, 7, 1, uaInfo, NULL)) - { - ret = 1; - } - } - SAFE_MUTEX_UNLOCK(&emu_key_data_mutex); - - return ret; -} - -int8_t powervu_emm(uint8_t *emm, uint32_t *keysAdded) -{ - uint8_t emmInfo, emmType, decryptOk = 0; - uint8_t emmKey[7], tmpEmmKey[7], tmp[26]; - uint16_t emmLen = SCT_LEN(emm); - uint32_t i, uniqueAddress, groupId, keyRef = 0; - //uint32_t emmCrc32; - char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[16]; - - if (emmLen < 50) - { - return EMU_NOT_SUPPORTED; - } - - // Check if unmasking is needed - if ((emm[3] & 0xF0) == 0x50) - { - unmask_emm(emm); - } - - // looks like checksum does not work for all EMMs - //emmCrc32 = b2i(4, emm+emmLen-4); - // - //if(ccitt32_crc(emm, emmLen-4) != emmCrc32) - //{ - // return EMU_CHECKSUM_ERROR; - //} - emmLen -= 4; - - uniqueAddress = b2i(4, emm + 12); - snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%.8X", uniqueAddress); - - do - { - if (!get_emm_key(emmKey, keyName, keyRef++, &groupId)) - { - //cs_log_dbg(D_ATR, "EMM key for UA %s is missing", keyName); - return EMU_KEY_NOT_FOUND; - } - - for (i = 19; i + 27 <= emmLen; i += 27) - { - emmInfo = emm[i]; - - if (!get_bit(emmInfo, 7)) - { - continue; - } - - //keyNb = emm[i] & 0x0F; - - memcpy(tmp, emm + i + 1, 26); - memcpy(tmpEmmKey, emmKey, 7); - powervu_decrypt(emm + i + 1, 26, tmpEmmKey, 0); - - if ((emm[13] != emm[i + 24]) || (emm[14] != emm[i + 25]) || (emm[15] != emm[i + 26])) - { - memcpy(emm + i + 1, tmp, 26); - memcpy(tmpEmmKey, emmKey, 7); - powervu_decrypt(emm + i + 1, 26, tmpEmmKey, 1); - - if ((emm[13] != emm[i + 24]) || (emm[14] != emm[i + 25]) || (emm[15] != emm[i + 26])) - { - memcpy(emm + i + 1, tmp, 26); - memcpy(tmpEmmKey, emmKey, 7); - continue; - } - } - - decryptOk = 1; - - emmType = emm[i + 2] & 0x7F; - - if (emmType > 1) - { - continue; - } - - if (emm[i + 3] == 0 && emm[i + 4] == 0) - { - cs_hexdump(0, &emm[i + 3], 7, keyValue, sizeof(keyValue)); - cs_log("Key found in EMM: P %04X**** %02X %s -> REJECTED (looks invalid) UA: %08X", - groupId, emmType, keyValue, uniqueAddress); - continue; - } - - update_ecm_keys_by_group(groupId, emmType, &emm[i + 3], uniqueAddress); - - (*keysAdded)++; - cs_hexdump(0, &emm[i + 3], 7, keyValue, sizeof(keyValue)); - cs_log("Key found in EMM: P %04X**** %02X %s ; UA: %08X", groupId, emmType, keyValue, uniqueAddress); - } - - } while (!decryptOk); - - return EMU_OK; -} - -int8_t powervu_get_hexserials(uint8_t hexserials[][4], uint32_t maxCount, uint16_t srvid) -{ - //srvid == 0xFFFF -> get all - - int8_t alreadyAdded; - uint8_t tmp[4]; - uint32_t i, j, k, groupid, length, count = 0; - KeyDataContainer *KeyDB; - - KeyDB = emu_get_key_container('P'); - if (KeyDB == NULL) - { - return 0; - } - - for (i = 0; i < KeyDB->keyCount && count < maxCount; i++) - { - if (KeyDB->EmuKeys[i].provider <= 0x0000FFFF) // skip EMM keys - { - continue; - } - - if (srvid != 0xFFFF && (KeyDB->EmuKeys[i].provider & 0x0000FFFF) != srvid) - { - continue; - } - - // This "groupid" has an ECM key with our "srvid" - // (in ECM keys "groupid" is top 16 bits) - groupid = KeyDB->EmuKeys[i].provider >> 16; - - for (j = 0; j < KeyDB->keyCount && count < maxCount; j++) - { - // Skip EMM keys belonging to other groups - // (in EMM keys "groupid" is bottom 16 bits) - if (KeyDB->EmuKeys[j].provider != groupid) - { - continue; - } - - length = cs_strlen(KeyDB->EmuKeys[j].keyName); - - if (length < 3) - { - continue; - } - - if (length > 8) - { - length = 8; - } - - memset(tmp, 0, 4); - char_to_bin(tmp + (4 - (length / 2)), KeyDB->EmuKeys[j].keyName, length); - - for (k = 0, alreadyAdded = 0; k < count; k++) - { - if (!memcmp(hexserials[k], tmp, 4)) - { - alreadyAdded = 1; - break; - } - } - - if (!alreadyAdded) - { - memcpy(hexserials[count], tmp, 4); - count++; - } - } - } - - return count; -} - -int8_t powervu_get_hexserials_new(uint8_t hexserials[][4], uint32_t maxCount, uint16_t caid, - uint16_t tsid, uint16_t onid, uint32_t ens) -{ - int8_t alreadyAdded; - uint8_t tmp[4]; - uint32_t i, j, channel_hash, group_id, length, count = 0; - KeyDataContainer *KeyDB; - - KeyDB = emu_get_key_container('P'); - if (KeyDB == NULL) - { - return 0; - } - - channel_hash = create_channel_hash(caid, tsid, onid, ens); - group_id = get_channel_group(channel_hash); - - if (group_id == 0) // No group found for this hash - { - return 0; - } - - for (i = 0; i < KeyDB->keyCount && count < maxCount; i++) - { - // Skip EMM keys belonging to other groups - // (in EMM keys "groupid" is bottom 16 bits) - if (KeyDB->EmuKeys[i].provider != group_id) - { - continue; - } - - length = cs_strlen(KeyDB->EmuKeys[i].keyName); - - if (length < 3) - { - continue; - } - - if (length > 8) - { - length = 8; - } - - memset(tmp, 0, 4); - char_to_bin(tmp + (4 - (length / 2)), KeyDB->EmuKeys[i].keyName, length); - - for (j = 0, alreadyAdded = 0; j < count; j++) - { - if (!memcmp(hexserials[j], tmp, 4)) - { - alreadyAdded = 1; - break; - } - } - - if (!alreadyAdded) - { - memcpy(hexserials[count], tmp, 4); - count++; - } - } - - return count; -} - -#endif // WITH_EMU diff --git a/module-emulator-powervu.h b/module-emulator-powervu.h deleted file mode 100755 index b50d208..0000000 --- a/module-emulator-powervu.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef MODULE_EMULATOR_POWERVU_H -#define MODULE_EMULATOR_POWERVU_H - -#ifdef WITH_EMU - -#define PVU_CW_VID 0 // VIDeo -#define PVU_CW_HSD 1 // High Speed Data -#define PVU_CW_A1 2 // Audio 1 -#define PVU_CW_A2 3 // Audio 2 -#define PVU_CW_A3 4 // Audio 3 -#define PVU_CW_A4 5 // Audio 4 -#define PVU_CW_UTL 6 // UTiLity -#define PVU_CW_VBI 7 // Vertical Blanking Interval - -#define PVU_CONVCW_VID_ECM 0x80 // VIDeo -#define PVU_CONVCW_HSD_ECM 0x40 // High Speed Data -#define PVU_CONVCW_A1_ECM 0x20 // Audio 1 -#define PVU_CONVCW_A2_ECM 0x10 // Audio 2 -#define PVU_CONVCW_A3_ECM 0x08 // Audio 3 -#define PVU_CONVCW_A4_ECM 0x04 // Audio 4 -#define PVU_CONVCW_UTL_ECM 0x02 // UTiLity -#define PVU_CONVCW_VBI_ECM 0x01 // Vertical Blanking Interval - -#ifdef MODULE_STREAMRELAY -int8_t powervu_ecm(uint8_t *ecm, uint8_t *dw, EXTENDED_CW *cw_ex, uint16_t srvid, uint16_t caid, uint16_t tsid, uint16_t onid, uint32_t ens, emu_stream_client_key_data *cdata); -#else -int8_t powervu_ecm(uint8_t *ecm, uint8_t *dw, EXTENDED_CW *cw_ex, uint16_t srvid, uint16_t caid, uint16_t tsid, uint16_t onid, uint32_t ens); -#endif -int8_t powervu_emm(uint8_t *emm, uint32_t *keysAdded); - -/* - * This function searches for EMM keys and adds their Unique Addresses (UA) as EMM filters. - * The EMM keys are picked from all group id's that have ECM keys for the srvid specified - * as input. If there is a large ammount of EMM keys matching these criteria, only the first - * "maxCount" UA's are added as EMM filters. The rest are not used at all. - * - * In the rare case where two or more EMM keys with the same UA belong to different groups, - * and these groups also have ECM keys for the srvid in request, there is a chance the ECM - * keys in the "wrong" group to be updated. This is because the EMM algorithm has no way of - * knowing in which group the service id belongs to. A workaround for this designing flaw - * is to make sure there are no EMM keys with the same UA between different groups. - * - * Hexserials must be of type "uint8_t hexserials[maxCount][4]". If srvid is equal to 0xFFFF - * all serials are added (no service id filtering is done). Returns the count of hexserials - * added as filters. -*/ -int8_t powervu_get_hexserials(uint8_t hexserials[][4], uint32_t maxCount, uint16_t srvid); - -/* - * Like the previous function, it adds UAs as EMM filters. It is used in conjunction with the - * new method of entering ECM keys, where one key can serve every channel in the group. Since - * there is no srvid to search for, we need to know the group id prior to searching for EMM - * keys. To do so, this function calulates a hash using the tsid, onid and enigma namespace of - * the transponder, which is only available in enigma2. - * - * Hexserials must be of type "uint8_t hexserials[maxCount][4]" like before. It returns the - * count of hexserials added as filters. -*/ -int8_t powervu_get_hexserials_new(uint8_t hexserials[][4], uint32_t maxCount, uint16_t caid, uint16_t tsid, uint16_t onid, uint32_t ens); - -#endif // WITH_EMU - -#endif // MODULE_EMULATOR_POWERVU_H diff --git a/module-emulator-viaccess.c b/module-emulator-viaccess.c deleted file mode 100755 index b5fea65..0000000 --- a/module-emulator-viaccess.c +++ /dev/null @@ -1,1183 +0,0 @@ -#define MODULE_LOG_PREFIX "emu" - -#include "globals.h" - -#ifdef WITH_EMU - -#include "cscrypt/des.h" -#include "module-emulator-osemu.h" -#include "module-newcamd-des.h" -#include "oscam-aes.h" -#include "oscam-string.h" - -// from reader-viaccess.c: -void hdSurEncPhase1_D2_0F_11(uint8_t *CWs); -void hdSurEncPhase2_D2_0F_11(uint8_t *CWs); -void hdSurEncPhase1_D2_13_15(uint8_t *cws); -void hdSurEncPhase2_D2_13_15(uint8_t *cws); - -// Viaccess EMU - -static int8_t get_key(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, - uint32_t keyLength, uint8_t isCriticalKey) -{ - char keyStr[EMU_MAX_CHAR_KEYNAME]; - snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); - - if (emu_find_key('V', ident, 0, keyStr, buf, keyLength, isCriticalKey, 0, 0, NULL)) - { - return 1; - } - - if (ident == 0xD00040 && emu_find_key('V', 0x030B00, 0, keyStr, buf, keyLength, isCriticalKey, 0, 0, NULL)) - { - return 1; - } - - return 0; -} - -static void via1_mod(const uint8_t *key2, uint8_t *data) -{ - int32_t kb, db; - - for (db = 7; db >= 0; db--) - { - for (kb = 7; kb > 3; kb--) - { - int32_t a0 = kb ^ db; - int32_t pos = 7; - - if (a0 & 4) - { - a0 ^= 7; - pos ^= 7; - } - - a0 = (a0 ^ (kb & 3)) + (kb & 3); - - if (!(a0 & 4)) - { - data[db] ^= (key2[kb] ^ ((data[kb ^ pos] * key2[kb ^ 4]) & 0xFF)); - } - } - } - - for (db = 0; db < 8; db++) - { - for (kb = 0; kb < 4; kb++) - { - int32_t a0 = kb ^ db; - int32_t pos = 7; - - if (a0 & 4) - { - a0 ^= 7; - pos ^= 7; - } - - a0 = (a0 ^ (kb & 3)) + (kb & 3); - - if (!(a0 & 4)) - { - data[db] ^= (key2[kb] ^ ((data[kb ^ pos] * key2[kb ^ 4]) & 0xFF)); - } - } - } -} - -static void via1_decode(uint8_t *data, uint8_t *key) -{ - via1_mod(key + 8, data); - nc_des(key, DES_ECM_CRYPT, data); - via1_mod(key + 8, data); -} - -static void via1_hash(uint8_t *data, uint8_t *key) -{ - via1_mod(key + 8, data); - nc_des(key, DES_ECM_HASH, data); - via1_mod(key + 8, data); -} - -static inline void via1_do_hash(uint8_t *hashbuffer, uint8_t *pH, uint8_t data, uint8_t *hashkey) -{ - hashbuffer[*pH] ^= data; - (*pH)++; - - if (*pH == 8) - { - via1_hash(hashbuffer, hashkey); - *pH = 0; - } -} - -static int8_t via1_decrypt(uint8_t *ecm, uint8_t *dw, uint32_t ident, uint8_t desKeyIndex) -{ - int32_t msg_pos, encStart = 0, hash_start, i; - - uint8_t tmp, k, pH, foundData = 0; - uint8_t work_key[16], signature[8], hashbuffer[8], prepared_key[16], hashkey[16]; - uint8_t *data, *des_data1, *des_data2; - - uint16_t ecmLen = SCT_LEN(ecm); - - if (ident == 0) - { - return EMU_CORRUPT_DATA; - } - - memset(work_key, 0, 16); - - if (!get_key(work_key, ident, '0', desKeyIndex, 8, 1)) - { - return EMU_KEY_NOT_FOUND; - } - - if (ecmLen < 11) - { - return EMU_NOT_SUPPORTED; - } - - data = ecm + 9; - des_data1 = dw; - des_data2 = dw + 8; - - msg_pos = 0; - pH = 0; - memset(hashbuffer, 0, sizeof(hashbuffer)); - memcpy(hashkey, work_key, sizeof(hashkey)); - memset(signature, 0, 8); - - while (9 + msg_pos + 2 < ecmLen) - { - switch (data[msg_pos]) - { - case 0xEA: - if (9 + msg_pos + 2 + 15 < ecmLen) - { - encStart = msg_pos + 2; - memcpy(des_data1, &data[msg_pos + 2], 8); - memcpy(des_data2, &data[msg_pos + 2 + 8], 8); - foundData |= 1; - } - break; - - case 0xF0: - if (9 + msg_pos + 2 + 7 < ecmLen) - { - memcpy(signature, &data[msg_pos + 2], 8); - foundData |= 2; - } - break; - } - msg_pos += data[msg_pos + 1] + 2; - } - - if (foundData != 3) - { - return EMU_NOT_SUPPORTED; - } - - pH = i = 0; - - if (data[0] == 0x9F && 10 + data[1] <= ecmLen) - { - via1_do_hash(hashbuffer, &pH, data[i++], hashkey); - via1_do_hash(hashbuffer, &pH, data[i++], hashkey); - - for (hash_start = 0; hash_start < data[1]; hash_start++) - { - via1_do_hash(hashbuffer, &pH, data[i++], hashkey); - } - - while (pH != 0) - { - via1_do_hash(hashbuffer, &pH, 0, hashkey); - } - } - - if (work_key[7] == 0) - { - for (; i < encStart + 16; i++) - { - via1_do_hash(hashbuffer, &pH, data[i], hashkey); - } - memcpy(prepared_key, work_key, 8); - } - else - { - prepared_key[0] = work_key[2]; - prepared_key[1] = work_key[3]; - prepared_key[2] = work_key[4]; - prepared_key[3] = work_key[5]; - prepared_key[4] = work_key[6]; - prepared_key[5] = work_key[0]; - prepared_key[6] = work_key[1]; - prepared_key[7] = work_key[7]; - - memcpy(prepared_key + 8, work_key + 8, 8); - - if (work_key[7] & 1) - { - for (; i < encStart; i++) - { - via1_do_hash(hashbuffer, &pH, data[i], hashkey); - } - - k = ((work_key[7] & 0xF0) == 0) ? 0x5A : 0xA5; - - for (i = 0; i < 8; i++) - { - tmp = des_data1[i]; - des_data1[i] = (k & hashbuffer[pH] ) ^ tmp; - via1_do_hash(hashbuffer, &pH, tmp, hashkey); - } - - for (i = 0; i < 8; i++) - { - tmp = des_data2[i]; - des_data2[i] = (k & hashbuffer[pH] ) ^ tmp; - via1_do_hash(hashbuffer, &pH, tmp, hashkey); - } - } - else - { - for ( ; i < encStart + 16; i++) - { - via1_do_hash(hashbuffer, &pH, data[i], hashkey); - } - } - } - - via1_decode(des_data1, prepared_key); - via1_decode(des_data2, prepared_key); - via1_hash(hashbuffer, hashkey); - - if (memcmp(signature, hashbuffer, 8)) - { - return EMU_CHECKSUM_ERROR; - } - - return EMU_OK; -} - -static int8_t via26_process_dw(uint8_t *indata, uint32_t ident, uint8_t desKeyIndex) -{ - uint8_t pv1,pv2, i; - uint8_t Tmp[8], T1Key[300], P1Key[8], KeyDes1[16], KeyDes2[16], XorKey[8]; - uint32_t ks1[32], ks2[32]; - - if (!get_key(T1Key, ident, 'T', 1, 300, 1)) - { - return 2; - } - - if (!get_key(P1Key, ident, 'P', 1, 8, 1)) - { - return 2; - } - - if (!get_key(KeyDes1, ident, 'D', 1, 16, 1)) - { - return 2; - } - - if (!get_key(KeyDes2, ident, '0', desKeyIndex, 16, 1)) - { - return 2; - } - - if (!get_key(XorKey, ident, 'X', 1, 8, 1)) - { - return 2; - } - - for (i = 0; i < 8; i++) - { - pv1 = indata[i]; - Tmp[i] = T1Key[pv1]; - } - - for (i = 0; i < 8; i++) - { - pv1 = P1Key[i]; - pv2 = Tmp[pv1]; - indata[i] = pv2; - } - - des_set_key(KeyDes1, ks1); - des(indata, ks1, 1); - - for (i = 0; i < 8; i++) - { - indata[i] ^= XorKey[i]; - } - - des_set_key(KeyDes2, ks1); - des_set_key(KeyDes2 + 8, ks2); - des(indata, ks1, 0); - des(indata, ks2, 1); - des(indata, ks1, 0); - - for (i = 0; i < 8; i++) - { - indata[i] ^= XorKey[i]; - } - - des_set_key(KeyDes1, ks1); - des(indata, ks1, 0); - - for (i = 0; i < 8; i++) - { - pv1 = indata[i]; - pv2 = P1Key[i]; - Tmp[pv2] = pv1; - } - - for (i = 0; i < 8; i++) - { - pv1 = Tmp[i]; - pv2 = T1Key[pv1]; - indata[i] = pv2; - } - - return 0; -} - -static int8_t via26_decrypt(uint8_t *source, uint8_t *dw, uint32_t ident, uint8_t desKeyIndex) -{ - uint8_t tmpData[8], C1[8]; - uint8_t *pXorVector; - int32_t i, j; - - if (ident == 0) - { - return EMU_CORRUPT_DATA; - } - - if (!get_key(C1, ident, 'C', 1, 8, 1)) - { - return EMU_KEY_NOT_FOUND; - } - - for (i = 0; i < 2; i++) - { - memcpy(tmpData, source + i * 8, 8); - via26_process_dw(tmpData, ident, desKeyIndex); - - if (i != 0) - { - pXorVector = source; - } - else - { - pXorVector = &C1[0]; - } - - for (j = 0; j < 8; j++) - { - dw[i * 8 + j] = tmpData[j] ^ pXorVector[j]; - } - - // Fix CW checksum bytes - for (j = 3; j < 8; j += 4) - { - dw[i * 8 + j] = (dw[i * 8 + j - 3] + dw[i * 8 + j - 2] + dw[i * 8 + j - 1]) & 0xFF; - } - } - - return EMU_OK; -} - -static void via3_core(uint8_t *data, uint8_t Off, uint32_t ident, uint8_t *XorKey, uint8_t *T1Key) -{ - uint8_t i; - uint32_t lR2, lR3, lR4, lR6, lR7; - - switch (ident) - { - case 0x032820: - { - for (i = 0; i < 4; i++) - { - data[i] ^= XorKey[(Off + i) & 0x07]; - } - - lR2 = (data[0] ^ 0xBD) + data[0]; - lR3 = (data[3] ^ 0xEB) + data[3]; - lR2 = (lR2 - lR3) ^ data[2]; - lR3 = ((0x39 * data[1]) << 2); - data[4] = (lR2 | lR3) + data[2]; - - lR3 = ((((data[0] + 6) ^ data[0]) | (data[2] << 1)) ^ 0x65) + data[0]; - lR2 = (data[1] ^ 0xED) + data[1]; - lR7 = ((data[3] + 0x29) ^ data[3]) * lR2; - data[5] = lR7 + lR3; - - lR2 = ((data[2] ^ 0x33) + data[2]) & 0x0A; - lR3 = (data[0] + 0xAD) ^ data[0]; - lR3 = lR3 + lR2; - lR2 = data[3] * data[3]; - lR7 = (lR2 | 1) + data[1]; - data[6] = (lR3 | lR7) + data[1]; - - lR3 = data[1] & 0x07; - lR2 = (lR3 - data[2]) & (data[0] | lR2 | 0x01); - data[7] = lR2 + data[3]; - - for (i = 0; i < 4; i++) - { - data[i + 4] = T1Key[data[i + 4]]; - } - } - break; - - case 0x030B00: - { - for (i = 0; i < 4; i++) - { - data[i] ^= XorKey[(Off + i) & 0x07]; - } - - lR6 = (data[3] + 0x6E) ^ data[3]; - lR6 = (lR6 * (data[2] << 1)) + 0x17; - lR3 = (data[1] + 0x77) ^ data[1]; - lR4 = (data[0] + 0xD7) ^ data[0]; - data[4] = ((lR4 & lR3) | lR6) + data[0]; - - lR4 = ((data[3] + 0x71) ^ data[3]) ^ 0x90; - lR6 = (data[1] + 0x1B) ^ data[1]; - lR4 = (lR4 * lR6) ^ data[0]; - data[5] = (lR4 ^ (data[2] << 1)) + data[1]; - - lR3 = (data[3] * data[3]) | 0x01; - lR4 = (((data[2] ^ 0x35) + data[2]) | lR3) + data[2]; - lR6 = data[1] ^ (data[0] + 0x4A); - data[6] = lR6 + lR4; - - lR3 = (data[0] * (data[2] << 1)) | data[1]; - lR4 = 0xFE - data[3]; - lR3 = lR4 ^ lR3; - data[7] = lR3 + data[3]; - - for (i = 0; i < 4; i++) - { - data[4 + i] = T1Key[data[4 + i]]; - } - } - break; - - default: - break; - } -} - -static void via3_fct1(uint8_t *data, uint32_t ident, uint8_t *XorKey, uint8_t *T1Key) -{ - uint8_t t; - - via3_core(data, 0, ident, XorKey, T1Key); - - switch (ident) - { - case 0x032820: - { - t = data[4]; - data[4] = data[7]; - data[7] = t; - } - break; - - case 0x030B00: - { - t = data[5]; - data[5] = data[7]; - data[7] = t; - } - break; - - default: - break; - } -} - -static void via3_fct2(uint8_t *data, uint32_t ident, uint8_t *XorKey, uint8_t *T1Key) -{ - uint8_t t; - - via3_core(data, 4, ident, XorKey, T1Key); - - switch (ident) - { - case 0x032820: - { - t = data[4]; - data[4] = data[7]; - data[7] = data[5]; - data[5] = data[6]; - data[6] = t; - } - break; - - case 0x030B00: - { - t = data[6]; - data[6] = data[7]; - data[7] = t; - } - break; - - default: - break; - } -} - -static int8_t via3_process_dw(uint8_t *data, uint32_t ident, uint8_t desKeyIndex) -{ - uint8_t i; - uint8_t tmp[8], T1Key[300], P1Key[8], KeyDes[16], XorKey[8]; - uint32_t ks1[32], ks2[32]; - - if (!get_key(T1Key, ident, 'T', 1, 300, 1)) - { - return 2; - } - - if (!get_key(P1Key, ident, 'P', 1, 8, 1)) - { - return 2; - } - - if (!get_key(KeyDes, ident, '0', desKeyIndex, 16, 1)) - { - return 2; - } - - if (!get_key(XorKey, ident, 'X', 1, 8, 1)) - { - return 2; - } - - for (i = 0; i < 4; i++) - { - tmp[i] = data[i + 4]; - } - - via3_fct1(tmp, ident, XorKey, T1Key); - - for (i = 0; i < 4; i++) - { - tmp[i] = data[i] ^ tmp[i + 4]; - } - - via3_fct2(tmp, ident, XorKey, T1Key); - - for (i = 0; i < 4; i++) - { - tmp[i] ^= XorKey[i + 4]; - } - - for (i = 0; i < 4; i++) - { - data[i] = data[i + 4] ^ tmp[i + 4]; - data[i + 4] = tmp[i]; - } - - des_set_key(KeyDes, ks1); - des_set_key(KeyDes + 8, ks2); - - des(data, ks1, 0); - des(data, ks2, 1); - des(data, ks1, 0); - - for (i = 0; i < 4; i++) - { - tmp[i] = data[i + 4]; - } - - via3_fct2(tmp, ident, XorKey, T1Key); - - for (i = 0; i < 4; i++) - { - tmp[i] = data[i] ^ tmp[i + 4]; - } - - via3_fct1(tmp, ident, XorKey, T1Key); - - for (i = 0; i < 4; i++) - { - tmp[i] ^= XorKey[i]; - } - - for (i = 0; i < 4; i++) - { - data[i] = data[i + 4] ^ tmp[i + 4]; - data[i + 4] = tmp[i]; - } - - return 0; -} - -static void via3_final_mix(uint8_t *dw) -{ - uint8_t tmp[4]; - - memcpy(tmp, dw, 4); - memcpy(dw, dw + 4, 4); - memcpy(dw + 4, tmp, 4); - - memcpy(tmp, dw + 8, 4); - memcpy(dw + 8, dw + 12, 4); - memcpy(dw + 12, tmp, 4); -} - -static int8_t via3_decrypt(uint8_t *source, uint8_t *dw, uint32_t ident, uint8_t desKeyIndex, - uint8_t aesKeyIndex, uint8_t aesMode, int8_t doFinalMix) -{ - int8_t aesAfterCore = 0, needsAES = (aesKeyIndex != 0xFF); - int32_t i, j; - - uint8_t tmpData[8], C1[8]; - uint8_t *pXorVector; - - char aesKey[16]; - - if (ident == 0) - { - return EMU_CORRUPT_DATA; - } - - if (!get_key(C1, ident, 'C', 1, 8, 1)) - { - return EMU_KEY_NOT_FOUND; - } - - if (needsAES && !get_key((uint8_t *)aesKey, ident, 'E', aesKeyIndex, 16, 1)) - { - return EMU_KEY_NOT_FOUND; - } - - if (aesMode == 0x0D || aesMode == 0x11 || aesMode == 0x15) - { - aesAfterCore = 1; - } - - if (needsAES && !aesAfterCore) - { - if (aesMode == 0x0F) - { - hdSurEncPhase1_D2_0F_11(source); - hdSurEncPhase2_D2_0F_11(source); - } - else if (aesMode == 0x13) - { - hdSurEncPhase1_D2_13_15(source); - } - - struct aes_keys aes; - aes_set_key(&aes, aesKey); - aes_decrypt(&aes, source, 16); - - if (aesMode == 0x0F) - { - hdSurEncPhase1_D2_0F_11(source); - } - else if (aesMode == 0x13) - { - hdSurEncPhase2_D2_13_15(source); - } - } - - for (i = 0; i < 2; i++) - { - memcpy(tmpData, source + i * 8, 8); - via3_process_dw(tmpData, ident, desKeyIndex); - - if (i != 0) - { - pXorVector = source; - } - else - { - pXorVector = &C1[0]; - } - - for (j = 0; j < 8; j++) - { - dw[i * 8 + j] = tmpData[j] ^ pXorVector[j]; - } - } - - if (needsAES && aesAfterCore) - { - if (aesMode == 0x11) - { - hdSurEncPhase1_D2_0F_11(dw); - hdSurEncPhase2_D2_0F_11(dw); - } - else if (aesMode == 0x15) - { - hdSurEncPhase1_D2_13_15(dw); - } - - struct aes_keys aes; - aes_set_key(&aes, aesKey); - aes_decrypt(&aes, dw, 16); - - if (aesMode == 0x11) - { - hdSurEncPhase1_D2_0F_11(dw); - } - - if (aesMode == 0x15) - { - hdSurEncPhase2_D2_13_15(dw); - } - } - - if (ident == 0x030B00) - { - if (doFinalMix) - { - via3_final_mix(dw); - } - - if (!is_valid_dcw(dw) || !is_valid_dcw(dw + 8)) - { - return EMU_CHECKSUM_ERROR; - } - } - - return EMU_OK; -} - -int8_t viaccess_ecm(uint8_t *ecm, uint8_t *dw) -{ - int8_t doFinalMix = 0; - - uint8_t nanoCmd = 0, nanoLen = 0, version = 0, providerKeyLen = 0; - uint8_t desKeyIndex = 0, aesMode = 0, aesKeyIndex = 0xFF; - uint16_t i = 0, keySelectPos = 0, ecmLen = SCT_LEN(ecm); - uint32_t currentIdent = 0; - - for (i = 4; i + 2 < ecmLen; ) - { - nanoCmd = ecm[i++]; - nanoLen = ecm[i++]; - - if (i + nanoLen > ecmLen) - { - return EMU_NOT_SUPPORTED; - } - - switch (nanoCmd) - { - case 0x40: - if (nanoLen < 0x03) - { - break; - } - version = ecm[i]; - if (nanoLen == 3) - { - currentIdent = ((ecm[i] << 16) | (ecm[i + 1] << 8)) | (ecm[i + 2] & 0xF0); - desKeyIndex = ecm[i + 2] & 0x0F; - keySelectPos = i + 3; - } - else - { - currentIdent = (ecm[i] << 16) | (ecm[i + 1] << 8) | ((ecm[i + 2] >> 4) & 0x0F); - desKeyIndex = ecm[i + 3]; - keySelectPos = i + 4; - } - providerKeyLen = nanoLen; - break; - - case 0x90: - if (nanoLen < 0x03) - { - break; - } - version = ecm[i]; - currentIdent = ((ecm[i] << 16) | (ecm[i + 1] << 8)) | (ecm[i + 2] & 0xF0); - desKeyIndex = ecm[i + 2] & 0x0F; - keySelectPos = i + 4; - if ((version == 3) && (nanoLen > 3)) - { - desKeyIndex = ecm[i + (nanoLen - 4)] & 0x0F; - } - providerKeyLen = nanoLen; - break; - - case 0x80: - nanoLen = 0; - break; - - case 0xD2: - if (nanoLen < 0x02) - { - break; - } - aesMode = ecm[i]; - aesKeyIndex = ecm[i + 1]; - break; - - case 0xDD: - nanoLen = 0; - break; - - case 0xEA: - if (nanoLen < 0x10) - { - break; - } - if (version < 2) - { - return via1_decrypt(ecm, dw, currentIdent, desKeyIndex); - } - else if (version == 2) - { - return via26_decrypt(ecm + i, dw, currentIdent, desKeyIndex); - } - else if (version == 3) - { - doFinalMix = 0; - if (currentIdent == 0x030B00 && providerKeyLen > 3) - { - if (keySelectPos + 2 >= ecmLen) - { - break; - } - if (ecm[keySelectPos] == 0x05 && ecm[keySelectPos + 1] == 0x67 && - (ecm[keySelectPos + 2] == 0x00 || ecm[keySelectPos + 2] == 0x01)) - { - if (ecm[keySelectPos + 2] == 0x01) - { - doFinalMix = 1; - } - } - else - { - break; - } - } - - return via3_decrypt(ecm + i, dw, currentIdent, desKeyIndex, aesKeyIndex, aesMode, doFinalMix); - } - break; - - default: - break; - } - - i += nanoLen; - } - - return EMU_NOT_SUPPORTED; -} - -// Viaccess EMM EMU - -int8_t viaccess_emm(uint8_t *emm, uint32_t *keysAdded) -{ - uint8_t nanoCmd = 0, subNanoCmd = 0, *tmp; - uint8_t ecmKeyCount = 0, emmKeyIndex = 0, aesMode = 0x0D; - uint8_t nanoLen = 0, subNanoLen = 0, haveEmmXorKey = 0, haveNewD0 = 0; - uint8_t ecmKeys[6][16], keyD0[2], emmKey[16], emmXorKey[16], provName[17]; - - uint16_t i = 0, j = 0, k = 0, emmLen = SCT_LEN(emm); - uint32_t ui1, ui2, ui3, ecmKeyIndex[6], provider = 0, ecmProvider = 0; - - char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[36]; - struct aes_keys aes; - - memset(keyD0, 0, 2); - memset(ecmKeyIndex, 0, sizeof(uint32_t) * 6); - - for (i = 3; i + 2 < emmLen; ) - { - nanoCmd = emm[i++]; - nanoLen = emm[i++]; - - if (i + nanoLen > emmLen) - { - return EMU_NOT_SUPPORTED; - } - - switch (nanoCmd) - { - case 0x90: - { - if (nanoLen < 3) - { - break; - } - - ui1 = emm[i + 2]; - ui2 = emm[i + 1]; - ui3 = emm[i]; - provider = (ui1 | (ui2 << 8) | (ui3 << 16)); - - if (provider == 0x00D00040) - { - ecmProvider = 0x030B00; - } - else - { - return EMU_NOT_SUPPORTED; - } - break; - } - - case 0xD2: - { - if (nanoLen < 2) - { - break; - } - - emmKeyIndex = emm[i + 1]; - break; - } - - case 0x41: - { - if (nanoLen < 1) - { - break; - } - - if (!get_key(emmKey, provider, 'M', emmKeyIndex, 16, 1)) - { - return EMU_KEY_NOT_FOUND; - } - - memset(provName, 0, 17); - memset(emmXorKey, 0, 16); - - k = nanoLen < 16 ? nanoLen : 16; - - memcpy(provName, &emm[i], k); - aes_set_key(&aes, (char *)emmKey); - aes_decrypt(&aes, emmXorKey, 16); - - for (j = 0; j < 16; j++) - { - provName[j] ^= emmXorKey[j]; - } - provName[k] = 0; - - if (strcmp((char *)provName, "TNTSAT") != 0 && - strcmp((char *)provName, "TNTSATPRO") != 0 && - strcmp((char *)provName, "CSAT V") != 0) - { - return EMU_NOT_SUPPORTED; - } - - break; - } - - case 0xBA: - { - if (nanoLen < 2) - { - break; - } - - get_key(keyD0, ecmProvider, 'D', 0, 2, 0); - - ui1 = (emm[i] << 8) | emm[i + 1]; - - if( (uint32_t)((keyD0[0] << 8) | keyD0[1]) < ui1 || (keyD0[0] == 0x00 && keyD0[1] == 0x00)) - { - keyD0[0] = emm[i]; - keyD0[1] = emm[i + 1]; - haveNewD0 = 1; - break; - } - - return EMU_OK; - } - - case 0xBC: - { - break; - } - - case 0x43: - { - if (nanoLen < 16) - { - break; - } - - memcpy(emmXorKey, &emm[i], 16); - haveEmmXorKey = 1; - - break; - } - - case 0x44: - { - if (nanoLen < 3) - { - break; - } - - if (!haveEmmXorKey) - { - memset(emmXorKey, 0, 16); - } - - tmp = (uint8_t *)malloc(((nanoLen / 16) + 1) * 16 * sizeof(uint8_t)); - if (tmp == NULL) - { - return EMU_OUT_OF_MEMORY; - } - - memcpy(tmp, &emm[i], nanoLen); - aes_set_key(&aes, (char *)emmKey); - - for (j = 0; j < nanoLen; j += 16) - { - aes_decrypt(&aes, emmXorKey, 16); - - for (k = 0; k < 16; k++) - { - tmp[j + k] ^= emmXorKey[k]; - } - } - - memcpy(&emm[i - 2], tmp, nanoLen); - free(tmp); - nanoLen = 0; - i -= 2; - break; - } - - case 0x68: - { - if (ecmKeyCount > 5) - { - break; - } - - for (j = i; j + 2 < i + nanoLen; ) - { - subNanoCmd = emm[j++]; - subNanoLen = emm[j++]; - - if (j + subNanoLen > i + nanoLen) - { - break; - } - - switch (subNanoCmd) - { - case 0xD2: - { - if (nanoLen < 2) - { - break; - } - - aesMode = emm[j]; - emmKeyIndex = emm[j + 1]; - break; - } - - case 0x01: - { - if(nanoLen < 17) - { - break; - } - - ecmKeyIndex[ecmKeyCount] = emm[j]; - memcpy(&ecmKeys[ecmKeyCount], &emm[j + 1], 16); - - if (!get_key(emmKey, provider, 'M', emmKeyIndex, 16, 1)) - { - break; - } - - if (aesMode == 0x0F || aesMode == 0x11) - { - hdSurEncPhase1_D2_0F_11(ecmKeys[ecmKeyCount]); - hdSurEncPhase2_D2_0F_11(ecmKeys[ecmKeyCount]); - } - else if (aesMode == 0x13 || aesMode == 0x15) - { - hdSurEncPhase1_D2_13_15(ecmKeys[ecmKeyCount]); - } - - aes_set_key(&aes, (char *)emmKey); - aes_decrypt(&aes, ecmKeys[ecmKeyCount], 16); - - if (aesMode == 0x0F || aesMode == 0x11) - { - hdSurEncPhase1_D2_0F_11(ecmKeys[ecmKeyCount]); - } - else if (aesMode == 0x13 || aesMode == 0x15) - { - hdSurEncPhase2_D2_13_15(ecmKeys[ecmKeyCount]); - } - - ecmKeyCount++; - break; - } - - default: - break; - } - - j += subNanoLen; - } - break; - } - - case 0xF0: - { - if (nanoLen != 4) - { - break; - } - - ui1 = ((emm[i + 2] << 8) | (emm[i + 1] << 16) | (emm[i] << 24) | emm[i + 3]); - - if (ccitt32_crc(emm + 3, emmLen - 11) != ui1) - { - return EMU_CHECKSUM_ERROR; - } - - if (haveNewD0) - { - SAFE_MUTEX_LOCK(&emu_key_data_mutex); - emu_set_key('V', ecmProvider, "D0", keyD0, 2, 1, NULL, NULL); - - for (j = 0; j < ecmKeyCount; j++) - { - snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "E%X", ecmKeyIndex[j]); - emu_set_key('V', ecmProvider, keyName, ecmKeys[j], 16, 1, NULL, NULL); - - (*keysAdded)++; - cs_hexdump(0, ecmKeys[j], 16, keyValue, sizeof(keyValue)); - cs_log("Key found in EMM: V %06X %s %s", ecmProvider, keyName, keyValue); - } - SAFE_MUTEX_UNLOCK(&emu_key_data_mutex); - } - break; - } - - default: - break; - } - - i += nanoLen; - } - - return EMU_OK; -} - -#endif // WITH_EMU diff --git a/module-emulator-viaccess.h b/module-emulator-viaccess.h deleted file mode 100755 index 6f4afca..0000000 --- a/module-emulator-viaccess.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef MODULE_EMULATOR_VIACCESS_H -#define MODULE_EMULATOR_VIACCESS_H - -#ifdef WITH_EMU - -int8_t viaccess_ecm(uint8_t *ecm, uint8_t *dw); -int8_t viaccess_emm(uint8_t *emm, uint32_t *keysAdded); - -#endif // WITH_EMU - -#endif // MODULE_EMULATOR_VIACCESS_H diff --git a/module-emulator.c b/module-emulator.c deleted file mode 100755 index 865e668..0000000 --- a/module-emulator.c +++ /dev/null @@ -1,894 +0,0 @@ -#define MODULE_LOG_PREFIX "emu" - -#include "globals.h" - -#ifdef WITH_EMU - -#include "module-streamrelay.h" -#include "module-emulator-osemu.h" -#include "module-emulator-biss.h" -#include "module-emulator-irdeto.h" -#include "module-emulator-powervu.h" -#include "oscam-conf-chk.h" -#include "oscam-config.h" -#include "oscam-reader.h" -#include "oscam-string.h" - -/* - * Readers in OSCam consist of 2 basic parts. - * The hardware or the device part. This is where physical smart cards are inserted - * and made available to OSCam. - * The software or the emulation part. This is where the actual card reading is done, - * including ecm and emm processing (i.e emulation of the various cryptosystems). - * In the Emu reader, the device part has no meaning, but we have to create it in - * order to be compatible with OSCam's reader structure. -*/ - -/* - * Create the Emu "emulation" part. This is of type s_cardsystem. - * Similar structures are found in the main sources folder (files reader-xxxxxx.c) - * for every cryptosystem supported by OSCam. - * Here we read keys from our virtual card (aka the SoftCam.Key file) and we inform - * OSCam about them. This is done with the emu_card_info() function. Keep in mind - * that Emu holds all its keys to separate structures for faster access. - * In addition, ECM and EMM requests are processed here, with the emu_do_ecm() and - * emu_do_emm() functions. -*/ - -#define CS_OK 1 -#define CS_ERROR 0 - -extern char cs_confdir[128]; -#ifdef MODULE_STREAMRELAY -static int8_t emu_key_data_mutex_init = 0; -#endif -pthread_mutex_t emu_key_data_mutex; - -static void set_hexserial_to_version(struct s_reader *rdr) -{ - char cVersion[32]; - uint32_t version = EMU_VERSION; - uint8_t hversion[2]; - memset(hversion, 0, 2); - snprintf(cVersion, sizeof(cVersion), "%04d", version); - char_to_bin(hversion, cVersion, 4); - rdr->hexserial[3] = hversion[0]; - rdr->hexserial[4] = hversion[1]; -} - -static void set_prids(struct s_reader *rdr) -{ - int32_t i, j; - - rdr->nprov = 0; - - for (i = 0; (i < rdr->emu_auproviders.nfilts) && (rdr->nprov < CS_MAXPROV); i++) - { - for (j = 0; (j < rdr->emu_auproviders.filts[i].nprids) && (rdr->nprov < CS_MAXPROV); j++) - { - i2b_buf(4, rdr->emu_auproviders.filts[i].prids[j], rdr->prid[i]); - rdr->nprov++; - } - } -} - -static void emu_add_entitlement(struct s_reader *rdr, uint16_t caid, uint32_t provid, uint8_t *key, char *keyName, uint32_t keyLength, uint8_t isData) -{ - if (!rdr->ll_entitlements) - { - rdr->ll_entitlements = ll_create("ll_entitlements"); - } - - S_ENTITLEMENT *item; - if (cs_malloc(&item, sizeof(S_ENTITLEMENT))) - { - // fill item - item->caid = caid; - item->provid = provid; - item->id = 0; - item->class = 0; - item->start = 0; - item->end = 2147472000; - item->type = 0; - item->isKey = 1; - memcpy(item->name, keyName, 8); - item->key = key; - item->keyLength = keyLength; - item->isData = isData; - - // add item - ll_append(rdr->ll_entitlements, item); - } -} - -static void refresh_entitlements(struct s_reader *rdr) -{ - uint32_t i; - uint16_t caid; - KeyData *tmpKeyData; - LL_ITER itr; - biss2_rsa_key_t *item; - - cs_clear_entitlement(rdr); - - for (i = 0; i < StreamKeys.keyCount; i++) - { - emu_add_entitlement(rdr, b2i(2, StreamKeys.EmuKeys[i].key), StreamKeys.EmuKeys[i].provider, StreamKeys.EmuKeys[i].key, - StreamKeys.EmuKeys[i].keyName, StreamKeys.EmuKeys[i].keyLength, 1); - } - - for (i = 0; i < ViKeys.keyCount; i++) - { - emu_add_entitlement(rdr, 0x0500, ViKeys.EmuKeys[i].provider, ViKeys.EmuKeys[i].key, - ViKeys.EmuKeys[i].keyName, ViKeys.EmuKeys[i].keyLength, 0); - } - - for (i = 0; i < IrdetoKeys.keyCount; i++) - { - tmpKeyData = &IrdetoKeys.EmuKeys[i]; - do - { - emu_add_entitlement(rdr, tmpKeyData->provider >> 8, tmpKeyData->provider & 0xFF, - tmpKeyData->key, tmpKeyData->keyName, tmpKeyData->keyLength, 0); - - tmpKeyData = tmpKeyData->nextKey; - } - while (tmpKeyData != NULL); - } - - for (i = 0; i < CwKeys.keyCount; i++) - { - emu_add_entitlement(rdr, CwKeys.EmuKeys[i].provider >> 8, CwKeys.EmuKeys[i].provider & 0xFF, - CwKeys.EmuKeys[i].key, CwKeys.EmuKeys[i].keyName, CwKeys.EmuKeys[i].keyLength, 0); - } - - for (i = 0; i < PowervuKeys.keyCount; i++) - { - emu_add_entitlement(rdr, 0x0E00, PowervuKeys.EmuKeys[i].provider, PowervuKeys.EmuKeys[i].key, - PowervuKeys.EmuKeys[i].keyName, PowervuKeys.EmuKeys[i].keyLength, 0); - } - - for (i = 0; i < TandbergKeys.keyCount; i++) - { - emu_add_entitlement(rdr, 0x1010, TandbergKeys.EmuKeys[i].provider, TandbergKeys.EmuKeys[i].key, - TandbergKeys.EmuKeys[i].keyName, TandbergKeys.EmuKeys[i].keyLength, 0); - } - - for (i = 0; i < NagraKeys.keyCount; i++) - { - emu_add_entitlement(rdr, 0x1801, NagraKeys.EmuKeys[i].provider, NagraKeys.EmuKeys[i].key, - NagraKeys.EmuKeys[i].keyName, NagraKeys.EmuKeys[i].keyLength, 0); - } - - // Session words for BISS1 mode 1/E (caid 2600) and BISS2 mode 1/E (caid 2602) - for (i = 0; i < BissSWs.keyCount; i++) - { - caid = (BissSWs.EmuKeys[i].keyLength == 8) ? 0x2600 : 0x2602; - emu_add_entitlement(rdr, caid, BissSWs.EmuKeys[i].provider, BissSWs.EmuKeys[i].key, - BissSWs.EmuKeys[i].keyName, BissSWs.EmuKeys[i].keyLength, 0); - } - - // Session keys (ECM keys) for BISS2 mode CA - for (i = 0; i < Biss2Keys.keyCount; i++) - { - emu_add_entitlement(rdr, 0x2610, Biss2Keys.EmuKeys[i].provider, Biss2Keys.EmuKeys[i].key, - Biss2Keys.EmuKeys[i].keyName, Biss2Keys.EmuKeys[i].keyLength, 0); - } - - // RSA keys (EMM keys) for BISS2 mode CA - itr = ll_iter_create(rdr->ll_biss2_rsa_keys); - while ((item = ll_iter_next(&itr))) - { - emu_add_entitlement(rdr, 0x2610, 0, item->ekid, "RSAPRI", 8, 0); - } - - for (i = 0; i < OmnicryptKeys.keyCount; i++) - { - emu_add_entitlement(rdr, 0x00FF, OmnicryptKeys.EmuKeys[i].provider, OmnicryptKeys.EmuKeys[i].key, - OmnicryptKeys.EmuKeys[i].keyName, OmnicryptKeys.EmuKeys[i].keyLength, 0); - } -} - -static int32_t emu_do_ecm(struct s_reader *rdr, const ECM_REQUEST *er, struct s_ecm_answer *ea) -{ - if (!emu_process_ecm(rdr, er, ea->cw, &ea->cw_ex)) - { - return CS_OK; - } - - return CS_ERROR; -} - -static int32_t emu_do_emm(struct s_reader *rdr, EMM_PACKET *emm) -{ - uint32_t keysAdded = 0; - - if (emm->emmlen < 3) - { - return CS_ERROR; - } - - if (SCT_LEN(emm->emm) > emm->emmlen) - { - return CS_ERROR; - } - - if (!emu_process_emm(rdr, b2i(2, emm->caid), emm->emm, &keysAdded)) - { - if (keysAdded > 0) - { - refresh_entitlements(rdr); - } - - return CS_OK; - } - - return CS_ERROR; -} - -static int32_t emu_card_info(struct s_reader *rdr) -{ - SAFE_MUTEX_LOCK(&emu_key_data_mutex); - - // Delete keys from Emu's memory - emu_clear_keydata(); - - // Delete BISS2 mode CA RSA keys - ll_destroy_data(&rdr->ll_biss2_rsa_keys); - - // Read keys built in the OSCam-Emu binary - emu_read_keymemory(rdr); - - // Read keys from SoftCam.Key file - emu_set_keyfile_path(cs_confdir); - - if (!emu_read_keyfile(rdr, cs_confdir)) - { - if (emu_read_keyfile(rdr, "/var/keys/")) - { - emu_set_keyfile_path("/var/keys/"); - } - } - - // Read BISS2 mode CA RSA keys from PEM files - biss_read_pem(rdr, BISS2_MAX_RSA_KEYS); - - cs_log("Total keys in memory: W:%d V:%d N:%d I:%d F:%d G:%d O:%d P:%d T:%d A:%d", - CwKeys.keyCount, ViKeys.keyCount, NagraKeys.keyCount, IrdetoKeys.keyCount, BissSWs.keyCount, - Biss2Keys.keyCount, OmnicryptKeys.keyCount, PowervuKeys.keyCount, TandbergKeys.keyCount, - StreamKeys.keyCount); - - // Inform OSCam about all available keys. - // This is used for listing the "entitlements" in the webif's reader page. - refresh_entitlements(rdr); - - SAFE_MUTEX_UNLOCK(&emu_key_data_mutex); - - set_prids(rdr); - - set_hexserial_to_version(rdr); - - return CS_OK; -} - -/* -static int32_t emu_card_init(struct s_reader *UNUSED(rdr), struct s_ATR *UNUSED(atr)) -{ - return CS_ERROR; -} -*/ - -int32_t emu_get_via3_emm_type(EMM_PACKET *ep, struct s_reader *rdr) -{ - uint32_t provid = 0; - - if(ep->emm[3] == 0x90 && ep->emm[4] == 0x03) - { - provid = b2i(3, ep->emm + 5); - provid &= 0xFFFFF0; - i2b_buf(4, provid, ep->provid); - } - - switch (ep->emm[0]) - { - case 0x88: - ep->type = UNIQUE; - memset(ep->hexserial, 0, 8); - memcpy(ep->hexserial, ep->emm + 4, 4); - rdr_log_dbg(rdr, D_EMM, "UNIQUE"); - return 1; - - case 0x8A: - case 0x8B: - ep->type = GLOBAL; - rdr_log_dbg(rdr, D_EMM, "GLOBAL"); - return 1; - - case 0x8C: - case 0x8D: - ep->type = SHARED; - rdr_log_dbg(rdr, D_EMM, "SHARED (part)"); - // We need those packets to pass otherwise we would never - // be able to complete EMM reassembly - return 1; - - case 0x8E: - ep->type = SHARED; - rdr_log_dbg(rdr, D_EMM, "SHARED"); - memset(ep->hexserial, 0, 8); - memcpy(ep->hexserial, ep->emm + 3, 3); - return 1; - - default: - ep->type = UNKNOWN; - rdr_log_dbg(rdr, D_EMM, "UNKNOWN"); - return 1; - } -} - -int32_t emu_get_ird2_emm_type(EMM_PACKET *ep, struct s_reader *rdr) -{ - int32_t l = (ep->emm[3] & 0x07); - int32_t base = (ep->emm[3] >> 3); - char dumprdrserial[l * 3], dumpemmserial[l * 3]; - - switch (l) - { - case 0: - // global emm, 0 bytes addressed - ep->type = GLOBAL; - rdr_log_dbg(rdr, D_EMM, "GLOBAL base = %02x", base); - return 1; - - case 2: - // shared emm, 2 bytes addressed - ep->type = SHARED; - memset(ep->hexserial, 0, 8); - memcpy(ep->hexserial, ep->emm + 4, l); - cs_hexdump(1, rdr->hexserial, l, dumprdrserial, sizeof(dumprdrserial)); - cs_hexdump(1, ep->hexserial, l, dumpemmserial, sizeof(dumpemmserial)); - rdr_log_dbg_sensitive(rdr, D_EMM, "SHARED l = %d ep = {%s} rdr = {%s} base = %02x", - l, dumpemmserial, dumprdrserial, base); - return 1; - - case 3: - // unique emm, 3 bytes addressed - ep->type = UNIQUE; - memset(ep->hexserial, 0, 8); - memcpy(ep->hexserial, ep->emm + 4, l); - cs_hexdump(1, rdr->hexserial, l, dumprdrserial, sizeof(dumprdrserial)); - cs_hexdump(1, ep->hexserial, l, dumpemmserial, sizeof(dumpemmserial)); - rdr_log_dbg_sensitive(rdr, D_EMM, "UNIQUE l = %d ep = {%s} rdr = {%s} base = %02x", - l, dumpemmserial, dumprdrserial, base); - return 1; - - default: - ep->type = UNKNOWN; - rdr_log_dbg(rdr, D_EMM, "UNKNOWN"); - return 1; - } -} - -int32_t emu_get_pvu_emm_type(EMM_PACKET *ep, struct s_reader *rdr) -{ - if (ep->emm[0] == 0x82) - { - ep->type = UNIQUE; - memset(ep->hexserial, 0, 8); - memcpy(ep->hexserial, ep->emm + 12, 4); - } - else - { - ep->type = UNKNOWN; - rdr_log_dbg(rdr, D_EMM, "UNKNOWN"); - } - return 1; -} - -int32_t emu_get_tan_emm_type(EMM_PACKET *ep, struct s_reader *rdr) -{ - if (ep->emm[0] == 0x82 || ep->emm[0] == 0x83) - { - ep->type = GLOBAL; - } - else - { - ep->type = UNKNOWN; - rdr_log_dbg(rdr, D_EMM, "UNKNOWN"); - } - return 1; -} - -int32_t emu_get_biss_emm_type(EMM_PACKET *ep, struct s_reader *rdr) -{ - switch (ep->emm[0]) - { - case 0x81: // Spec say this is for EMM, but oscam (and all other crypto systems) use it for ECM - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8A: - case 0x8B: - case 0x8C: - case 0x8D: - case 0x8E: - case 0x8F: - ep->type = GLOBAL; - return 1; - - default: - ep->type = UNKNOWN; - rdr_log_dbg(rdr, D_EMM, "UNKNOWN"); - return 1; - } -} - -static int32_t emu_get_emm_type(struct emm_packet_t *ep, struct s_reader *rdr) -{ - uint16_t caid = b2i(2, ep->caid); - - if (caid_is_viaccess(caid)) return emu_get_via3_emm_type(ep, rdr); - if (caid_is_irdeto(caid)) return emu_get_ird2_emm_type(ep, rdr); - if (caid_is_powervu(caid)) return emu_get_pvu_emm_type(ep, rdr); - if (caid_is_director(caid)) return emu_get_tan_emm_type(ep, rdr); - if (caid_is_biss_dynamic(caid)) return emu_get_biss_emm_type(ep, rdr); - - return CS_ERROR; -} - -FILTER *get_emu_prids_for_caid(struct s_reader *rdr, uint16_t caid) -{ - int32_t i; - - for (i = 0; i < rdr->emu_auproviders.nfilts; i++) - { - if (caid == rdr->emu_auproviders.filts[i].caid) - { - return &rdr->emu_auproviders.filts[i]; - } - } - - return NULL; -} - -static int32_t emu_get_via3_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t UNUSED(caid), uint32_t UNUSED(provid)) -{ - if (*emm_filters == NULL) - { - const unsigned int max_filter_count = 1; - if (!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter))) - { - return CS_ERROR; - } - - struct s_csystem_emm_filter *filters = *emm_filters; - *filter_count = 0; - - int32_t idx = 0; - - filters[idx].type = EMM_GLOBAL; - filters[idx].enabled = 1; - filters[idx].filter[0] = 0x8A; - filters[idx].mask[0] = 0xFE; - filters[idx].filter[3] = 0x80; - filters[idx].mask[3] = 0x80; - idx++; - - *filter_count = idx; - } - - return CS_OK; -} - -static int32_t emu_get_ird2_emm_filter(struct s_reader *rdr, struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t caid, uint32_t UNUSED(provid)) -{ - uint8_t hexserial[3], prid[4]; - FILTER *emu_provids; - int8_t have_provid = 0, have_serial = 0; - int32_t i; - - SAFE_MUTEX_LOCK(&emu_key_data_mutex); - if(irdeto2_get_hexserial(caid, hexserial)) - { - have_serial = 1; - } - SAFE_MUTEX_UNLOCK(&emu_key_data_mutex); - - emu_provids = get_emu_prids_for_caid(rdr, caid); - if (emu_provids != NULL && emu_provids->nprids > 0) - { - have_provid = 1; - } - - if (*emm_filters == NULL) - { - const unsigned int max_filter_count = have_serial + (2 * (have_provid ? emu_provids->nprids : 0)); - if (!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter))) - { - return CS_ERROR; - } - - struct s_csystem_emm_filter *filters = *emm_filters; - *filter_count = 0; - - unsigned int idx = 0; - - if (have_serial) - { - filters[idx].type = EMM_UNIQUE; - filters[idx].enabled = 1; - filters[idx].filter[0] = 0x82; - filters[idx].mask[0] = 0xFF; - filters[idx].filter[1] = 0xFB; - filters[idx].mask[1] = 0x07; - memcpy(&filters[idx].filter[2], hexserial, 3); - memset(&filters[idx].mask[2], 0xFF, 3); - idx++; - } - - for (i = 0; have_provid && i < emu_provids->nprids; i++) - { - i2b_buf(4, emu_provids->prids[i], prid); - - filters[idx].type = EMM_UNIQUE; - filters[idx].enabled = 1; - filters[idx].filter[0] = 0x82; - filters[idx].mask[0] = 0xFF; - filters[idx].filter[1] = 0xFB; - filters[idx].mask[1] = 0x07; - memcpy(&filters[idx].filter[2], &prid[1], 3); - memset(&filters[idx].mask[2], 0xFF, 3); - idx++; - - filters[idx].type = EMM_SHARED; - filters[idx].enabled = 1; - filters[idx].filter[0] = 0x82; - filters[idx].mask[0] = 0xFF; - filters[idx].filter[1] = 0xFA; - filters[idx].mask[1] = 0x07; - memcpy(&filters[idx].filter[2], &prid[1], 2); - memset(&filters[idx].mask[2], 0xFF, 2); - idx++; - } - - *filter_count = idx; - } - - return CS_OK; -} - -static int32_t emu_get_pvu_emm_filter(struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, - uint16_t caid, uint16_t srvid, uint16_t tsid, uint16_t onid, uint32_t ens) -{ - uint8_t hexserials[32][4]; - uint32_t i, count = 0; - - SAFE_MUTEX_LOCK(&emu_key_data_mutex); - count = powervu_get_hexserials_new(hexserials, 32, caid, tsid, onid, ens); - if (count == 0) - { - count = powervu_get_hexserials(hexserials, 32, srvid); - if (count == 0) - { - SAFE_MUTEX_UNLOCK(&emu_key_data_mutex); - return CS_ERROR; - } - } - SAFE_MUTEX_UNLOCK(&emu_key_data_mutex); - - if (*emm_filters == NULL) - { - const unsigned int max_filter_count = count; - if (!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter))) - { - return CS_ERROR; - } - - struct s_csystem_emm_filter *filters = *emm_filters; - *filter_count = 0; - - int32_t idx = 0; - - for (i = 0; i < count; i++) - { - filters[idx].type = EMM_UNIQUE; - filters[idx].enabled = 1; - filters[idx].filter[0] = 0x82; - filters[idx].filter[10] = hexserials[i][0]; - filters[idx].filter[11] = hexserials[i][1]; - filters[idx].filter[12] = hexserials[i][2]; - filters[idx].filter[13] = hexserials[i][3]; - filters[idx].mask[0] = 0xFF; - filters[idx].mask[10] = 0xFF; - filters[idx].mask[11] = 0xFF; - filters[idx].mask[12] = 0xFF; - filters[idx].mask[13] = 0xFF; - idx++; - } - - *filter_count = idx; - } - - return CS_OK; -} - -static int32_t emu_get_tan_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t UNUSED(caid), uint32_t UNUSED(provid)) -{ - if (*emm_filters == NULL) - { - const unsigned int max_filter_count = 2; - uint8_t buf[8]; - - if (!emu_find_key('T', 0x40, 0, "MK", buf, 8, 0, 0, 0, NULL) && - !emu_find_key('T', 0x40, 0, "MK01", buf, 8, 0, 0, 0, NULL)) - { - return CS_ERROR; - } - - if (!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter))) - { - return CS_ERROR; - } - - struct s_csystem_emm_filter *filters = *emm_filters; - *filter_count = 0; - - int32_t idx = 0; - - filters[idx].type = EMM_GLOBAL; - filters[idx].enabled = 1; - filters[idx].filter[0] = 0x82; - filters[idx].mask[0] = 0xFF; - idx++; - - filters[idx].type = EMM_GLOBAL; - filters[idx].enabled = 1; - filters[idx].filter[0] = 0x83; - filters[idx].mask[0] = 0xFF; - idx++; - - *filter_count = idx; - } - - return CS_OK; -} - -static int32_t emu_get_biss_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t UNUSED(caid), uint32_t UNUSED(provid)) -{ - if (*emm_filters == NULL) - { - const unsigned int max_filter_count = 15; - if (!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter))) - { - return CS_ERROR; - } - - struct s_csystem_emm_filter *filters = *emm_filters; - *filter_count = 0; - - int32_t idx = 0; - uint8_t i; - - for (i = 0; i < max_filter_count; i++) - { - filters[idx].type = EMM_GLOBAL; - filters[idx].enabled = 1; - filters[idx].filter[0] = 0x81 + i; // What about table 0x81? - filters[idx].mask[0] = 0xFF; - idx++; - - *filter_count = idx; - } - } - return CS_OK; -} - -static int32_t emu_get_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **UNUSED(emm_filters), unsigned int *UNUSED(filter_count)) -{ - return CS_ERROR; -} - -static int32_t emu_get_emm_filter_adv(struct s_reader *rdr, struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, - uint16_t caid, uint32_t provid, uint16_t srvid, uint16_t tsid, uint16_t onid, uint32_t ens) -{ - if (caid_is_viaccess(caid)) return emu_get_via3_emm_filter(rdr, emm_filters, filter_count, caid, provid); - if (caid_is_irdeto(caid)) return emu_get_ird2_emm_filter(rdr, emm_filters, filter_count, caid, provid); - if (caid_is_powervu(caid)) return emu_get_pvu_emm_filter(emm_filters, filter_count, caid, srvid, tsid, onid, ens); - if (caid_is_director(caid)) return emu_get_tan_emm_filter(rdr, emm_filters, filter_count, caid, provid); - if (caid_is_biss_dynamic(caid)) return emu_get_biss_emm_filter(rdr, emm_filters, filter_count, caid, provid); - - return CS_ERROR; -} - -const struct s_cardsystem reader_emu = -{ - .desc = "emu", - .caids = (uint16_t[]){ 0x05, 0x06, 0x0D, 0x0E, 0x10, 0x18, 0x26, 0 }, - .do_ecm = emu_do_ecm, - .do_emm = emu_do_emm, - .card_info = emu_card_info, - //.card_init = emu_card_init, // apparently this is not needed at all - .get_emm_type = emu_get_emm_type, - .get_emm_filter = emu_get_emm_filter, // needed to pass checks - .get_emm_filter_adv = emu_get_emm_filter_adv, -}; - -/* - * Create the Emu virtual "device" part. This is of type s_cardreader. - * Similar structures are found in the csctapi (Card System Card Terminal API) - * folder for every IFD (InterFace Device), aka smart card reader. - * Since we have no hardware to initialize, we start our Stream Relay server - * with the emu_reader_init() function. - * At Emu shutdown, we remove keys from memory with the emu_close() function. -*/ - -#define CR_OK 0 -#define CR_ERROR 1 - -static int32_t emu_reader_init(struct s_reader *UNUSED(reader)) -{ -#ifdef MODULE_STREAMRELAY - if (cfg.stream_relay_enabled && (stream_server_thread_init == 0)) - { - int32_t i; - stream_server_thread_init = 1; - SAFE_MUTEX_INIT(&emu_fixed_key_srvid_mutex, NULL); - - for (i = 0; i < EMU_STREAM_SERVER_MAX_CONNECTIONS; i++) - { - SAFE_MUTEX_INIT(&emu_fixed_key_data_mutex[i], NULL); - ll_emu_stream_delayed_keys[i] = ll_create("ll_emu_stream_delayed_keys"); - memset(&emu_fixed_key_data[i], 0, sizeof(emu_stream_client_key_data)); - } - - start_thread("stream_key_delayer", stream_key_delayer, NULL, NULL, 1, 1); - cs_log("Stream key delayer initialized"); - } - - // Initialize mutex for exclusive access to key database and key file - if (!emu_key_data_mutex_init) - { - SAFE_MUTEX_INIT(&emu_key_data_mutex, NULL); - emu_key_data_mutex_init = 1; - } -#endif - return CR_OK; -} - -static int32_t emu_close(struct s_reader *UNUSED(reader)) -{ - cs_log("Reader is shutting down"); - - // Delete keys from Emu's memory - SAFE_MUTEX_LOCK(&emu_key_data_mutex); - emu_clear_keydata(); - SAFE_MUTEX_UNLOCK(&emu_key_data_mutex); - - return CR_OK; -} - -static int32_t emu_get_status(struct s_reader *UNUSED(reader), int32_t *in) { *in = 1; return CR_OK; } -static int32_t emu_activate(struct s_reader *UNUSED(reader), struct s_ATR *UNUSED(atr)) { return CR_OK; } -static int32_t emu_transmit(struct s_reader *UNUSED(reader), uint8_t *UNUSED(buffer), uint32_t UNUSED(size), uint32_t UNUSED(expectedlen), uint32_t UNUSED(delay), uint32_t UNUSED(timeout)) { return CR_OK; } -static int32_t emu_receive(struct s_reader *UNUSED(reader), uint8_t *UNUSED(buffer), uint32_t UNUSED(size), uint32_t UNUSED(delay), uint32_t UNUSED(timeout)) { return CR_OK; } -static int32_t emu_write_settings(struct s_reader *UNUSED(reader), struct s_cardreader_settings *UNUSED(s)) { return CR_OK; } -static int32_t emu_card_write(struct s_reader *UNUSED(pcsc_reader), const uint8_t *UNUSED(buf), uint8_t *UNUSED(cta_res), uint16_t *UNUSED(cta_lr), int32_t UNUSED(l)) { return CR_OK; } -static int32_t emu_set_protocol(struct s_reader *UNUSED(rdr), uint8_t *UNUSED(params), uint32_t *UNUSED(length), uint32_t UNUSED(len_request)) { return CR_OK; } - -const struct s_cardreader cardreader_emu = -{ - .desc = "emu", - .typ = R_EMU, - .skip_extra_atr_parsing = 1, - .reader_init = emu_reader_init, - .get_status = emu_get_status, - .activate = emu_activate, - .transmit = emu_transmit, - .receive = emu_receive, - .close = emu_close, - .write_settings = emu_write_settings, - .card_write = emu_card_write, - .set_protocol = emu_set_protocol, -}; - -void add_emu_reader(void) -{ - // This function is called inside oscam.c and creates an emu [reader] with default - // settings in oscam.server file. If an emu [reader] already exists, it uses that. - - LL_ITER itr; - struct s_reader *rdr; - int8_t haveEmuReader = 0; - char emuName[] = "emulator"; - char *ctab, *ftab, *emu_auproviders, *disablecrccws_only_for; - - // Check if emu [reader] entry already exists in oscam.server file and get it - itr = ll_iter_create(configured_readers); - while ((rdr = ll_iter_next(&itr))) - { - if (rdr->typ == R_EMU) - { - haveEmuReader = 1; - break; - } - } - - rdr = NULL; - - // If there's no emu [reader] in oscam.server, create one with default settings - if (!haveEmuReader) - { - if (!cs_malloc(&rdr, sizeof(struct s_reader))) - { - return; - } - - reader_set_defaults(rdr); - - rdr->enable = 1; - rdr->typ = R_EMU; - cs_strncpy(rdr->label, emuName, sizeof(emuName)); - cs_strncpy(rdr->device, emuName, sizeof(emuName)); - - // CAIDs - ctab = strdup("0500,0604,0D00,0E00,1010,1801,2600,2602,2610"); - chk_caidtab(ctab, &rdr->ctab); - NULLFREE(ctab); - - // Idents - ftab = strdup("0500:020A00,021110;" - "0604:000000;" - "0D00:0000C0;" - "0E00:000000;" - "1010:000000;" - "1801:000000,001101,002111,007301;" - "2600:000000;" - "2602:000000;" - "2610:000000;" - ); - chk_ftab(ftab, &rdr->ftab); - NULLFREE(ftab); - - // AU providers - emu_auproviders = strdup("0604:010200;0E00:000000;1010:000000;2610:000000;"); - chk_ftab(emu_auproviders, &rdr->emu_auproviders); - NULLFREE(emu_auproviders); - - // EMM cache - rdr->cachemm = 2; - rdr->rewritemm = 1; - rdr->logemm = 2; - rdr->deviceemm = 1; - - // User group - rdr->grp = 0x1ULL; - - // Add the "device" part to our emu reader - rdr->crdr = &cardreader_emu; - - // Disable CW checksum test for PowerVu - disablecrccws_only_for = strdup("0E00:000000"); - chk_ftab(disablecrccws_only_for, &rdr->disablecrccws_only_for); - NULLFREE(disablecrccws_only_for); - - reader_fixups_fn(rdr); - ll_append(configured_readers, rdr); - } - - // Set DVB Api delayer option -#ifdef HAVE_DVBAPI - if (cfg.dvbapi_enabled && cfg.dvbapi_delayer < 60) - { - cfg.dvbapi_delayer = 60; - } -#endif - - cs_log("OSCam-Emu version %d", EMU_VERSION); -} - -#endif // WITH_EMU diff --git a/module-gbox-cards.c b/module-gbox-cards.c old mode 100644 new mode 100755 diff --git a/module-gbox-cards.h b/module-gbox-cards.h old mode 100644 new mode 100755 diff --git a/module-gbox-helper.c b/module-gbox-helper.c old mode 100644 new mode 100755 diff --git a/module-gbox-helper.h b/module-gbox-helper.h old mode 100644 new mode 100755 diff --git a/module-gbox-remm.c b/module-gbox-remm.c old mode 100644 new mode 100755 diff --git a/module-gbox-remm.h b/module-gbox-remm.h old mode 100644 new mode 100755 diff --git a/module-gbox-sms.c b/module-gbox-sms.c old mode 100644 new mode 100755 diff --git a/module-gbox-sms.h b/module-gbox-sms.h old mode 100644 new mode 100755 diff --git a/module-gbox.c b/module-gbox.c old mode 100644 new mode 100755 diff --git a/module-gbox.h b/module-gbox.h old mode 100644 new mode 100755 diff --git a/module-ghttp.c b/module-ghttp.c old mode 100644 new mode 100755 diff --git a/module-lcd.c b/module-lcd.c old mode 100644 new mode 100755 diff --git a/module-lcd.h b/module-lcd.h old mode 100644 new mode 100755 diff --git a/module-led.c b/module-led.c old mode 100644 new mode 100755 diff --git a/module-led.h b/module-led.h old mode 100644 new mode 100755 diff --git a/module-monitor.c b/module-monitor.c old mode 100644 new mode 100755 diff --git a/module-monitor.h b/module-monitor.h old mode 100644 new mode 100755 diff --git a/module-newcamd-des.c b/module-newcamd-des.c old mode 100644 new mode 100755 diff --git a/module-newcamd-des.h b/module-newcamd-des.h old mode 100644 new mode 100755 diff --git a/module-newcamd.c b/module-newcamd.c old mode 100644 new mode 100755 diff --git a/module-newcamd.h b/module-newcamd.h old mode 100644 new mode 100755 diff --git a/module-pandora.c b/module-pandora.c old mode 100644 new mode 100755 diff --git a/module-radegast.c b/module-radegast.c old mode 100644 new mode 100755 diff --git a/module-scam.c b/module-scam.c old mode 100644 new mode 100755 diff --git a/module-serial.c b/module-serial.c old mode 100644 new mode 100755 diff --git a/module-stat.c b/module-stat.c old mode 100644 new mode 100755 diff --git a/module-stat.h b/module-stat.h old mode 100644 new mode 100755 diff --git a/module-streamrelay.c b/module-streamrelay.c old mode 100644 new mode 100755 diff --git a/module-streamrelay.h b/module-streamrelay.h old mode 100644 new mode 100755 diff --git a/module-webif-lib.c b/module-webif-lib.c old mode 100644 new mode 100755 diff --git a/module-webif-lib.h b/module-webif-lib.h old mode 100644 new mode 100755 diff --git a/module-webif-tpl.c b/module-webif-tpl.c old mode 100644 new mode 100755 diff --git a/module-webif-tpl.h b/module-webif-tpl.h old mode 100644 new mode 100755 diff --git a/module-webif.c b/module-webif.c old mode 100644 new mode 100755 diff --git a/module-webif.c.bak b/module-webif.c.bak old mode 100644 new mode 100755 diff --git a/module-webif.c.orig b/module-webif.c.orig deleted file mode 100755 index d348e00..0000000 --- a/module-webif.c.orig +++ /dev/null @@ -1,10342 +0,0 @@ -#define MODULE_LOG_PREFIX "webif" - -#include "globals.h" - -#ifdef WEBIF -// -// OSCam HTTP server module -// -#include -#include "cscrypt/md5.h" -#include "module-anticasc.h" -#include "module-cacheex.h" -#include "module-cccam.h" -#include "module-cccam-data.h" -#include "module-dvbapi.h" -#include "module-newcamd.h" -#include "module-stat.h" -#include "module-webif.h" -#include "module-webif-lib.h" -#include "module-webif-tpl.h" -#include "oscam-conf-mk.h" -#include "oscam-config.h" -#include "oscam-files.h" -#include "oscam-garbage.h" -#include "oscam-cache.h" -#include "oscam-client.h" -#include "oscam-lock.h" -#include "oscam-net.h" -#include "oscam-reader.h" -#include "oscam-string.h" -#include "oscam-time.h" -#include "oscam-work.h" -#include "oscam-ecm.h" // Dodano dla refresh_cw_vote_config -#ifdef MODULE_GBOX -#include "module-gbox-sms.h" -#include "module-gbox.h" -#include "module-gbox-cards.h" -#endif - -#ifdef WEBIF_WIKI -#include "webif/pages_wiki.h" -#endif - -extern const struct s_cardreader *cardreaders[]; -extern char cs_confdir[]; -extern uint32_t ecmcwcache_size; -extern uint32_t cfg_sidtab_generation; -extern int32_t exit_oscam; -extern uint8_t cacheex_peer_id[8]; - -extern char *entitlement_type[]; -extern char *RDR_CD_TXT[]; -int8_t isactive; -int32_t ssl_active = 0; -char noncekey[33]; -pthread_key_t getkeepalive; -static pthread_key_t getip; -pthread_key_t getssl; -static CS_MUTEX_LOCK http_lock; -CS_MUTEX_LOCK *lock_cs; - -static uint8_t useLocal = 1; -#define PRINTF_LOCAL_D useLocal ? "%'d" : "%d" -#define PRINTF_LOCAL_F useLocal ? "%'.0f" : "%.0f" -#define PRINTF_LOCAL_MB useLocal ? "%'.2f MB" : "%.2f MB" - -static int8_t httpthread_running = 0; -static pthread_t httpthread; -static int32_t sock; -enum refreshtypes { REFR_ACCOUNTS, REFR_READERS, REFR_CLIENTS, REFR_SERVER, REFR_ANTICASC, REFR_SERVICES }; - -//initialize structs for calculating cpu-usage depending on time between refresh of status_page -static struct pstat p_stat_cur; -static struct pstat p_stat_old; - -static bool use_srvid2 = false; - -/* constants for menuactivating */ -#define MNU_STATUS 0 -#define MNU_LIVELOG 1 -#define MNU_CONFIG 2 -#define MNU_READERS 3 -#define MNU_USERS 4 -#define MNU_SERVICES 5 -#define MNU_FILES 6 -#define MNU_FAILBAN 7 -#define MNU_CACHEEX 8 -#define MNU_SCRIPT 9 -#define MNU_SHUTDOWN 10 -#define MNU_TOTAL_ITEMS 11 // sum of items above - -/* constants for config.html submenuactivating */ -#define MNU_CFG_GLOBAL 0 -#define MNU_CFG_ANTICASC 1 -#define MNU_CFG_CACHE 2 -#define MNU_CFG_LOADBAL 3 -#define MNU_CFG_CAMD33 4 -#define MNU_CFG_CAMD35 5 -#define MNU_CFG_CAMD35TCP 6 -#define MNU_CFG_CCCAM 7 -#define MNU_CFG_NEWCAMD 8 -#define MNU_CFG_GBOX 9 -#define MNU_CFG_RADEGAST 10 -#define MNU_CFG_SCAM 11 -#define MNU_CFG_SERIAL 12 -#define MNU_CFG_DVBAPI 13 -#define MNU_CFG_LCD 14 -#define MNU_CFG_MONITOR 15 -#define MNU_CFG_WEBIF 16 -#define MNU_CFG_STREAMRELAY 17 - -/* constants for files.html submenuactivating */ -#define MNU_CFG_FVERSION 0 -#define MNU_CFG_FCONF 1 -#define MNU_CFG_FUSER 2 -#define MNU_CFG_FSERVER 3 -#define MNU_CFG_FSRVID 4 -#define MNU_CFG_FDVBAPI 5 -#define MNU_CFG_FACLOG 6 -#define MNU_CFG_FLOGFILE 7 -#define MNU_CFG_FUSERFILE 8 -#define MNU_CFG_FSERVICES 9 -#define MNU_CFG_FPROVID 10 -#define MNU_CFG_FTIERS 11 -#define MNU_CFG_FRATELIMIT 12 -#define MNU_CFG_FWHITELIST 13 -#define MNU_CFG_FSRVID2 14 -#define MNU_CFG_FFAKECWS 15 -#define MNU_CFG_FCSS 16 -#define MNU_CFG_FTWIN 17 -#define MNU_CFG_FKEYCW 18 - -/* constants for files.html for GBOX submenuactivating */ -#define MNU_GBX_FSCINF 19 -#define MNU_GBX_FSHRINF 20 -#define MNU_GBX_FSHRONL 21 -#define MNU_GBX_FVERS 22 -#define MNU_GBX_FATTACK 23 -#define MNU_GBX_FSMSLOG 24 -#define MNU_GBX_FSMSACK 25 -#define MNU_GBX_FSMSNACK 26 -#define MNU_GBX_FSTAINF 27 -#define MNU_GBX_FEXPINF 28 -#define MNU_GBX_INFOLOG 29 -#define MNU_CFG_FSOFTCAMKEY 30 - -#define MNU_CFG_TOTAL_ITEMS 31 // sum of items above. Use it for "All inactive" in function calls too. - -static void set_status_info_var(struct templatevars *vars, char *varname, int no_data, char *fmt, double value) -{ - if (no_data) - tpl_addVar(vars, TPLADD, varname, "N/A"); - else - tpl_printf(vars, TPLADD, varname, fmt, value); -} - -/* -* Creates vars Memory/CPU/OSCAM info in for status_page -* if check_available == 0 N/A will be displayed -* Bit mapping -* mem 0 total, 1 used & free, 2 buff, cached & free incl. buff, 3 share -* swap 4 total, 5 used & free, -* proc 6 count -* cpu 7 load -* oscam 8 vsize & rssize, 9 cpu user, 10 cpu sys, 11 cpu sum, 12 cpu refreshtime -* unused 13 - 15 -*/ -static void set_status_info(struct templatevars *vars, struct pstat stats){ - set_status_info_var(vars, "MEM_CUR_TOTAL", stats.check_available & (1 << 0), PRINTF_LOCAL_MB , (double)stats.mem_total/(1024.0*1024.0)); - set_status_info_var(vars, "MEM_CUR_FREE", stats.check_available & (1 << 1), PRINTF_LOCAL_MB , (double)stats.mem_free/(1024.0*1024.0)); - set_status_info_var(vars, "MEM_CUR_USED", stats.check_available & (1 << 1), PRINTF_LOCAL_MB , (double)stats.mem_used/(1024.0*1024.0)); - set_status_info_var(vars, "MEM_CUR_BUFF", stats.check_available & (1 << 2), PRINTF_LOCAL_MB , (double)stats.mem_buff/(1024.0*1024.0)); - set_status_info_var(vars, "MEM_CUR_CACHED", stats.check_available & (1 << 2), PRINTF_LOCAL_MB , (double)stats.mem_cached/(1024.0*1024.0)); - set_status_info_var(vars, "MEM_CUR_FREEM", stats.check_available & (1 << 2), PRINTF_LOCAL_MB , (double)stats.mem_freem/(1024.0*1024.0)); - set_status_info_var(vars, "MEM_CUR_SHARE", stats.check_available & (1 << 3), PRINTF_LOCAL_MB , (double)stats.mem_share/(1024.0*1024.0)); - set_status_info_var(vars, "MEM_CUR_TOTSW", stats.check_available & (1 << 4), PRINTF_LOCAL_MB , (double)stats.mem_total_swap/(1024.0*1024.0)); - set_status_info_var(vars, "MEM_CUR_FRESW", stats.check_available & (1 << 5), PRINTF_LOCAL_MB , (double)stats.mem_free_swap/(1024.0*1024.0)); - set_status_info_var(vars, "MEM_CUR_USESW", stats.check_available & (1 << 5), PRINTF_LOCAL_MB , (double)stats.mem_used_swap/(1024.0*1024.0)); - - set_status_info_var(vars, "SERVER_PROCS", stats.check_available & (1 << 6), PRINTF_LOCAL_F , stats.info_procs); - - set_status_info_var(vars, "CPU_LOAD_0", stats.check_available & (1 << 7), "%.2f" , stats.cpu_avg[0]); - set_status_info_var(vars, "CPU_LOAD_1", stats.check_available & (1 << 7), "%.2f" , stats.cpu_avg[1]); - set_status_info_var(vars, "CPU_LOAD_2", stats.check_available & (1 << 7), "%.2f" , stats.cpu_avg[2]); - - set_status_info_var(vars, "OSCAM_VMSIZE", stats.check_available & (1 << 8), PRINTF_LOCAL_MB , (double)stats.vsize/(1024.0*1024.0)); - set_status_info_var(vars, "OSCAM_RSSSIZE", stats.check_available & (1 << 8), PRINTF_LOCAL_MB , (double)stats.rss/(1024.0*1024.0)); - set_status_info_var(vars, "OSCAM_CPU_USER", stats.check_available & (1 << 9), "%.2f %%" , stats.cpu_usage_user); - set_status_info_var(vars, "OSCAM_CPU_SYS", stats.check_available & (1 << 10), "%.2f %%" , stats.cpu_usage_sys); - double sum_cpu = stats.cpu_usage_sys + stats.cpu_usage_user; - set_status_info_var(vars, "OSCAM_CPU_SUM", stats.check_available & (1 << 11), "%.2f %%" , sum_cpu); - - if (stats.check_available & (1 << 12)) - { - tpl_addVar(vars, TPLADD, "OSCAM_REFRESH" , "N/A"); - } - else - { - tpl_printf(vars, TPLADD, "OSCAM_REFRESH" , "%02"PRId64":%02"PRId64":%02"PRId64"h", - stats.gone_refresh / 3600, - (stats.gone_refresh / 60) % 60, - stats.gone_refresh % 60); - } -} - -static void clear_account_stats(struct s_auth *account) -{ - account->cwfound = 0; - account->cwcache = 0; - account->cwnot = 0; - account->cwtun = 0; - account->cwignored = 0; - account->cwtout = 0; - account->emmok = 0; - account->emmnok = 0; -#ifdef CW_CYCLE_CHECK - account->cwcycledchecked = 0; - account->cwcycledok = 0; - account->cwcyclednok = 0; - account->cwcycledign = 0; -#endif - cacheex_clear_account_stats(account); -} - -static void clear_all_account_stats(void) -{ - struct s_auth *account = cfg.account; - while(account) - { - clear_account_stats(account); - account = account->next; - } -} - -#ifdef CS_CACHEEX -static void cacheex_clear_all_stats(void) -{ - struct s_auth *account = cfg.account; - while(account) - { - cacheex_clear_account_stats(account); - account = account->next; - } - struct s_client *cl; - for(cl = first_client->next; cl ; cl = cl->next) - { - cacheex_clear_client_stats(cl); - ll_clear_data(cl->ll_cacheex_stats); - } - cacheex_clear_client_stats(first_client); -} -#endif - -static void clear_info_clients_stats(void) -{ - first_client->cwfound = 0; - first_client->cwcache = 0; - first_client->cwnot = 0; - first_client->cwtun = 0; - first_client->cwignored = 0; - first_client->cwtout = 0; - first_client->emmok = 0; - first_client->emmnok = 0; - cacheex_clear_client_stats(first_client); -} - -static void clear_info_readers_stats(void) -{ - int8_t i; - cs_writelock(__func__, &readerlist_lock); - LL_ITER itr = ll_iter_create(configured_readers); - struct s_reader *rdr; - while((rdr = ll_iter_next(&itr))) - { - rdr->webif_ecmsok = 0; - rdr->webif_ecmsnok = 0; - rdr->webif_ecmstout = 0; - rdr->webif_ecmsfilteredhead = 0; - rdr->webif_ecmsfilteredlen = 0; - - for(i = 0; i < 4; i++) - { - rdr->webif_emmerror[i] = 0; - rdr->webif_emmwritten[i] = 0; - rdr->webif_emmskipped[i] = 0; - rdr->webif_emmblocked[i] = 0; - } - } - cs_writeunlock(__func__, &readerlist_lock); -} - -static void set_ecm_info(struct templatevars * vars) -{ - //if one of the stats overloaded, reset all stats! - if(first_client->cwfound<0 - || first_client->cwnot<0 - || first_client->cwignored<0 - || first_client->cwtout<0 - || first_client->cwcache<0 - || first_client->cwtun<0 - || first_client->emmok<0 - || first_client->emmnok<0 -#ifdef CS_CACHEEX - || first_client->cwcacheexgot<0 - || first_client->cwcacheexpush<0 - || first_client->cwcacheexhit<0 -#ifdef CS_CACHEEX_AIO - || first_client->cwcacheexgotlg<0 - || first_client->cwcacheexpushlg<0 -#endif -#endif - ){ - clear_info_clients_stats(); - } - //end reset stats - - int ecm = 0, emm = 0; - double ecmsum = first_client->cwfound + first_client->cwcache + first_client->cwnot + first_client->cwtout; //dont count TUN its included - if(ecmsum < 1) {ecmsum = 1; ecm = 1;} - double ecmpos = first_client->cwfound + first_client->cwcache; // dont count TUN its included - if(ecmpos < 1) {ecmpos = 1;} - double ecmneg = first_client->cwnot + first_client->cwtout; //dont count IGN its not part of neagtiv - if(ecmneg < 1) {ecmneg = 1;} - double emmsum = first_client->emmok + first_client->emmnok; - if(emmsum < 1) {emmsum = 1; emm = 1;} - - tpl_printf(vars, TPLADD, "TOTAL_ECM_MIN", "%d", first_client->n_request[0]); - tpl_printf(vars, TPLADD, "TOTAL_CW", PRINTF_LOCAL_F, !ecm ? ecmsum : 0); - tpl_printf(vars, TPLADD, "TOTAL_CWOK", PRINTF_LOCAL_F, (double)first_client->cwfound); - tpl_printf(vars, TPLADD, "TOTAL_CWNOK", PRINTF_LOCAL_F, (double)first_client->cwnot); - tpl_printf(vars, TPLADD, "TOTAL_CWIGN", PRINTF_LOCAL_F, (double)first_client->cwignored); - tpl_printf(vars, TPLADD, "TOTAL_CWTOUT", PRINTF_LOCAL_F, (double)first_client->cwtout); - tpl_printf(vars, TPLADD, "TOTAL_CWCACHE", PRINTF_LOCAL_F, (double)first_client->cwcache); - tpl_printf(vars, TPLADD, "TOTAL_CWTUN", PRINTF_LOCAL_F, (double)first_client->cwtun); - tpl_printf(vars, TPLADD, "TOTAL_CWPOS", PRINTF_LOCAL_F, (double)first_client->cwfound + (double)first_client->cwcache); - tpl_printf(vars, TPLADD, "TOTAL_CWNEG", PRINTF_LOCAL_F, (double)first_client->cwnot + (double)first_client->cwtout); - tpl_printf(vars, TPLADD, "TOTAL_EM", PRINTF_LOCAL_F, !emm ? emmsum : 0); - tpl_printf(vars, TPLADD, "TOTAL_EMOK", PRINTF_LOCAL_F, (double)first_client->emmok); - tpl_printf(vars, TPLADD, "TOTAL_EMNOK", PRINTF_LOCAL_F, (double)first_client->emmnok); - tpl_printf(vars, TPLADD, "REL_CWOK", "%.2f", (double)first_client->cwfound * 100 / ecmsum); - tpl_printf(vars, TPLADD, "REL_CWNOK", "%.2f", (double)first_client->cwnot * 100 / ecmsum); - //tpl_printf(vars, TPLADD, "REL_CWIGN", "%.2f", (double)first_client->cwignored * 100 / ecmsum); - tpl_printf(vars, TPLADD, "REL_CWTOUT", "%.2f", (double)first_client->cwtout * 100 / ecmsum); - tpl_printf(vars, TPLADD, "REL_CWCACHE", "%.2f", (double)first_client->cwcache * 100 / ecmsum); - tpl_printf(vars, TPLADD, "REL_CWTUN", "%.2f", (double)first_client->cwtun * 100 / ecmsum); - tpl_printf(vars, TPLADD, "REL_CWPOS", "%.2f", (double)(first_client->cwfound + first_client->cwcache) * 100 / ecmsum); - tpl_printf(vars, TPLADD, "REL_CWNEG", "%.2f", (double)(first_client->cwnot + first_client->cwtout) * 100 / ecmsum); - tpl_printf(vars, TPLADD, "REL_EMOK", "%.2f", (double)first_client->emmok * 100 / emmsum); - tpl_printf(vars, TPLADD, "REL_EMNOK", "%.2f", (double)first_client->emmnok * 100 / emmsum); - tpl_printf(vars, TPLADD, "REL_CWPOSOK", "%.2f", (double)first_client->cwfound * 100 / ecmpos); - tpl_printf(vars, TPLADD, "REL_CWPOSCACHE", "%.2f", (double)first_client->cwcache * 100 / ecmpos); - tpl_printf(vars, TPLADD, "REL_CWNEGNOK", "%.2f", (double)first_client->cwnot * 100 / ecmneg); - //tpl_printf(vars, TPLADD, "REL_CWNEGIGN", "%.2f", (double)first_client->cwignored * 100 / ecmneg); - tpl_printf(vars, TPLADD, "REL_CWNEGTOUT", "%.2f", (double)first_client->cwtout * 100 / ecmneg); - - double totalrdrneg = 0, totalrdrpos = 0; - double totalrdrok = 0, totalrdrnok = 0, totalrdrtout = 0; - double flen = 0, fhead = 0; - double teruk = 0, terg = 0, ters = 0, teruq = 0; - double twruk = 0, twrg = 0, twrs = 0, twruq = 0; - double tskuk = 0, tskg = 0, tsks = 0, tskuq = 0; - double tbluk = 0, tblg = 0, tbls = 0, tbluq = 0; - - cs_readlock(__func__, &readerlist_lock); - LL_ITER itr = ll_iter_create(configured_readers); - struct s_reader *rdr; - while((rdr = ll_iter_next(&itr))) - { - if (rdr->webif_ecmsok) { totalrdrok += rdr->webif_ecmsok; } - if (rdr->webif_ecmsnok) { totalrdrnok += rdr->webif_ecmsnok; } - if (rdr->webif_ecmstout) { totalrdrtout += rdr->webif_ecmstout; } - - if (rdr->webif_ecmsfilteredlen) { flen += rdr->webif_ecmsfilteredlen; } - if (rdr->webif_ecmsfilteredhead) { fhead += rdr->webif_ecmsfilteredhead; } - - if (rdr->webif_emmerror[0]) { teruk += rdr->webif_emmerror[0]; } - if (rdr->webif_emmerror[1]) { teruq += rdr->webif_emmerror[1]; } - if (rdr->webif_emmerror[2]) { ters += rdr->webif_emmerror[2]; } - if (rdr->webif_emmerror[3]) { terg += rdr->webif_emmerror[3]; } - - if (rdr->webif_emmwritten[0]) { twruk += rdr->webif_emmwritten[0]; } - if (rdr->webif_emmwritten[1]) { twruq += rdr->webif_emmwritten[1]; } - if (rdr->webif_emmwritten[2]) { twrs += rdr->webif_emmwritten[2]; } - if (rdr->webif_emmwritten[3]) { twrg += rdr->webif_emmwritten[3]; } - - if (rdr->webif_emmskipped[0]) { tskuk += rdr->webif_emmskipped[0]; } - if (rdr->webif_emmskipped[1]) { tskuq += rdr->webif_emmskipped[1]; } - if (rdr->webif_emmskipped[2]) { tsks += rdr->webif_emmskipped[2]; } - if (rdr->webif_emmskipped[3]) { tskg += rdr->webif_emmskipped[3]; } - - if (rdr->webif_emmblocked[0]) { tbluk += rdr->webif_emmblocked[0]; } - if (rdr->webif_emmblocked[1]) { tbluq += rdr->webif_emmblocked[1]; } - if (rdr->webif_emmblocked[2]) { tbls += rdr->webif_emmblocked[2]; } - if (rdr->webif_emmblocked[3]) { tblg += rdr->webif_emmblocked[3]; } - } - cs_readunlock(__func__, &readerlist_lock); - - totalrdrneg = totalrdrnok + totalrdrtout; - totalrdrpos = totalrdrok; - ecmsum = totalrdrok + totalrdrnok + totalrdrtout; - - tpl_printf(vars, TPLADD, "TOTAL_CWOK_READERS", PRINTF_LOCAL_F, totalrdrok); - tpl_printf(vars, TPLADD, "TOTAL_CWNOK_READERS", PRINTF_LOCAL_F, totalrdrnok); - tpl_printf(vars, TPLADD, "TOTAL_CWTOUT_READERS", PRINTF_LOCAL_F, totalrdrtout); - tpl_printf(vars, TPLADD, "REL_CWOK_READERS", "%.2f", ecmsum ? totalrdrok * 100 / ecmsum : 0); - tpl_printf(vars, TPLADD, "REL_CWNOK_READERS", "%.2f", ecmsum ? totalrdrnok * 100 / ecmsum : 0); - tpl_printf(vars, TPLADD, "REL_CWTOUT_READERS", "%.2f", ecmsum ? totalrdrtout * 100 / ecmsum : 0); - tpl_printf(vars, TPLADD, "TOTAL_CWPOS_READERS", PRINTF_LOCAL_F, totalrdrpos); - tpl_printf(vars, TPLADD, "TOTAL_CWNEG_READERS", PRINTF_LOCAL_F, totalrdrneg); - tpl_printf(vars, TPLADD, "REL_CWPOS_READERS", "%.2f", ecmsum ? totalrdrpos * 100 / ecmsum : 0); - tpl_printf(vars, TPLADD, "REL_CWNEG_READERS", "%.2f", ecmsum ? totalrdrneg * 100 / ecmsum : 0); - tpl_printf(vars, TPLADD, "TOTAL_ELENR", PRINTF_LOCAL_F, flen); - tpl_printf(vars, TPLADD, "TOTAL_EHEADR", PRINTF_LOCAL_F, fhead); - tpl_printf(vars, TPLADD, "TOTAL_SUM_ALL_READERS_ECM", PRINTF_LOCAL_F, ecmsum); - - tpl_printf(vars, TPLADD, "TOTAL_EMMERRORUK_READERS", PRINTF_LOCAL_F, teruk); - tpl_printf(vars, TPLADD, "TOTAL_EMMERRORG_READERS", PRINTF_LOCAL_F, terg); - tpl_printf(vars, TPLADD, "TOTAL_EMMERRORS_READERS", PRINTF_LOCAL_F, ters); - tpl_printf(vars, TPLADD, "TOTAL_EMMERRORUQ_READERS", PRINTF_LOCAL_F, teruq); - tpl_printf(vars, TPLADD, "TOTAL_EMMWRITTENUK_READERS", PRINTF_LOCAL_F, twruk); - tpl_printf(vars, TPLADD, "TOTAL_EMMWRITTENG_READERS", PRINTF_LOCAL_F, twrg); - tpl_printf(vars, TPLADD, "TOTAL_EMMWRITTENS_READERS", PRINTF_LOCAL_F, twrs); - tpl_printf(vars, TPLADD, "TOTAL_EMMWRITTENUQ_READERS", PRINTF_LOCAL_F, twruq); - tpl_printf(vars, TPLADD, "TOTAL_EMMSKIPPEDUK_READERS", PRINTF_LOCAL_F, tskuk); - tpl_printf(vars, TPLADD, "TOTAL_EMMSKIPPEDG_READERS", PRINTF_LOCAL_F, tskg); - tpl_printf(vars, TPLADD, "TOTAL_EMMSKIPPEDS_READERS", PRINTF_LOCAL_F, tsks); - tpl_printf(vars, TPLADD, "TOTAL_EMMSKIPPEDUQ_READERS", PRINTF_LOCAL_F, tskuq); - tpl_printf(vars, TPLADD, "TOTAL_EMMBLOCKEDUK_READERS", PRINTF_LOCAL_F, tbluk); - tpl_printf(vars, TPLADD, "TOTAL_EMMBLOCKEDG_READERS", PRINTF_LOCAL_F, tblg); - tpl_printf(vars, TPLADD, "TOTAL_EMMBLOCKEDS_READERS", PRINTF_LOCAL_F, tbls); - tpl_printf(vars, TPLADD, "TOTAL_EMMBLOCKEDUQ_READERS", PRINTF_LOCAL_F, tbluq); - - emmsum = teruk + terg + ters + teruq + twruk + twrg + twrs + twruq + tskuk + tskg + tsks + tskuq + tbluk + tblg + tbls + tbluq; - - tpl_printf(vars, TPLADD, "TOTAL_SUM_ALL_READERS_EMM", PRINTF_LOCAL_F, emmsum); -} - -static void refresh_oscam(enum refreshtypes refreshtype) -{ - - switch(refreshtype) - { - case REFR_ACCOUNTS: - cs_log("Refresh Accounts requested by WebIF from %s", cs_inet_ntoa(GET_IP())); - cs_accounts_chk(); - break; - - case REFR_READERS: - cs_log("Refresh Readers requested by WebIF from %s", cs_inet_ntoa(GET_IP())); - reload_readerdb(); - break; - - case REFR_CLIENTS: - cs_log("Refresh Clients requested by WebIF from %s", cs_inet_ntoa(GET_IP())); - cs_reinit_clients(cfg.account); - break; - - case REFR_SERVER: - cs_log("Refresh Server requested by WebIF from %s", cs_inet_ntoa(GET_IP())); - reload_global_config(); // Wczytaj ponownie globalną konfigurację - break; - - case REFR_SERVICES: - cs_log("Refresh Services requested by WebIF from %s", cs_inet_ntoa(GET_IP())); - //init_sidtab(); - cs_accounts_chk(); - break; - -#ifdef CS_ANTICASC - case REFR_ANTICASC: - cs_log("Refresh Anticascading requested by WebIF from %s", cs_inet_ntoa(GET_IP())); - ac_init_stat(); - struct s_client *cl; - struct s_auth *account; - for(cl = first_client->next; cl ; cl = cl->next) - { - if(cl->typ == 'c' && (account = cl->account)) - { - cl->ac_limit = (account->ac_users * 100 + 80) * cfg.ac_stime; - } - } - break; -#endif - default: - break; - } -} -/* - * load historical values from ringbuffer and return it in the right order - * as string. Value should be freed with free_mk_t() - */ -static char *get_ecm_historystring(struct s_client *cl) -{ - - if(cl) - { - int32_t k, i, pos = 0, needed = 1, v; - char *value, *dot = ""; - int32_t ptr = cl->cwlastresptimes_last; - - needed = CS_ECM_RINGBUFFER_MAX * 6; //5 digits + delimiter - if(!cs_malloc(&value, needed)) { return ""; } - - k = ptr + 1; - for(i = 0; i < CS_ECM_RINGBUFFER_MAX; i++) - { - if(k >= CS_ECM_RINGBUFFER_MAX) - { k = 0; } - v = cl->cwlastresptimes[k].duration; - if(v > 0 && v < (int32_t)cfg.ctimeout * 5) - { - pos += snprintf(value + pos, needed - pos, "%s%d", dot, v); - dot = ","; - } - k++; - } - if(cs_strlen(value) == 0) - { - NULLFREE(value); - return ""; - } - else { return value; } - - } - else - { - return ""; - } -} - -static char *get_ecm_fullhistorystring(struct s_client *cl) -{ - - if(cl) - { - int32_t k, i, pos = 0, needed = 1, v; - char *value, *dot = ""; - int32_t ptr = cl->cwlastresptimes_last; - - needed = CS_ECM_RINGBUFFER_MAX * 20; //5 digits + : + returncode(2) + : + time(10) + delimiter - if(!cs_malloc(&value, needed)) { return ""; } - - k = ptr + 1; - for(i = 0; i < CS_ECM_RINGBUFFER_MAX; i++) - { - if(k >= CS_ECM_RINGBUFFER_MAX) - { k = 0; } - v = cl->cwlastresptimes[k].duration; - if(v > 0 && v < (int32_t)cfg.ctimeout * 5) - { - pos += snprintf(value + pos, needed - pos, "%s%d:%d:%" PRId64, dot, cl->cwlastresptimes[k].duration, cl->cwlastresptimes[k].rc, (int64_t)cl->cwlastresptimes[k].timestamp); - dot = ","; - } - k++; - } - - return (value); - - } - else - { - return ""; - } -} - -/* - * Set the active menu to a different CSS class - */ -static void setActiveMenu(struct templatevars *vars, int8_t active) -{ - int8_t i; - for(i = 0; i < MNU_TOTAL_ITEMS; i++) - { - tpl_printf(vars, TPLADD, "TMP", "MENUACTIVE%d", i); - if(i == active) - { tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "menu_selected"); } - else - { tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "menu"); } - } - #ifdef WEBIF_LIVELOG - tpl_addVar(vars, TPLADD, "LOGPAGEMENU", tpl_getTpl(vars, "LOGMENU")); - #endif -} - -/* - * Set the active submenu to a different CSS class - */ -static void setActiveSubMenu(struct templatevars *vars, int8_t active) -{ - int8_t i; - for(i = 0; i < MNU_CFG_TOTAL_ITEMS; i++) - { - tpl_printf(vars, TPLADD, "TMP", "CMENUACTIVE%d", i); - if(i == active) - { tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "configmenu_selected"); } - else - { tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "configmenu"); } - } -} - -static void webif_save_config(char *section, struct templatevars *vars, struct uriparams *params) -{ - if(!streq(getParam(params, "action"), "execute")) - { return; } - if(cfg.http_readonly) - { - tpl_addMsg(vars, "WebIf is in readonly mode. No changes are possible!"); - return; - } - int i; - int cnt = (*params).paramcount; - // First pass: check for checkbox values (value=1) to identify which checkboxes are checked - // This is needed because hidden fields (value=0) should not override checkbox values - bool *checkbox_checked = NULL; - if(cnt > 0 && !cs_malloc(&checkbox_checked, cnt * sizeof(bool))) - { - return; // Allocation failed, proceed with original behavior - } - for(i = 0; i < cnt; i++) - { - char *token = (*params).params[i]; - char *value = (*params).values[i]; - if(!streq(token, "part") && !streq(token, "action")) - { - // Check if this is a checkbox with value=1 - if(strcmp(value, "1") == 0) - { - checkbox_checked[i] = true; - } - } - } - // Second pass: apply settings, skip value=0 if checkbox is checked (hidden field) - for(i = 0; i < cnt; i++) - { - char *token = (*params).params[i]; - char *value = (*params).values[i]; - if(!streq(token, "part") && !streq(token, "action")) - { - // Skip hidden field value=0 if checkbox is checked (value=1 exists) - if(strcmp(value, "0") == 0) - { - bool checkbox_will_be_checked = false; - int j; - for(j = i + 1; j < cnt; j++) - { - if(strcmp((*params).params[j], token) == 0 && strcmp((*params).values[j], "1") == 0) - { - checkbox_will_be_checked = true; - break; - } - } - if(checkbox_will_be_checked) - { - continue; // Skip this hidden field, checkbox will set it to 1 - } - } - config_set(section, token, value); - } - } - free(checkbox_checked); - if(write_config() == 0) - { - tpl_addMsg(vars, "Configuration was saved."); - enum refreshtypes ref_type = REFR_SERVER; - if(streq(getParam(params, "part"), "anticasc")) - { ref_type = REFR_ANTICASC; } - refresh_oscam(ref_type); - } - else - { - tpl_addMsg(vars, "ERROR: Failed to write config file!!!"); - } -} - -static char *send_oscam_config_global(struct templatevars *vars, struct uriparams *params) -{ - setActiveSubMenu(vars, MNU_CFG_GLOBAL); - - webif_save_config("global", vars, params); - - if(IP_ISSET(cfg.srvip)) - { tpl_addVar(vars, TPLADD, "SERVERIP", cs_inet_ntoa(cfg.srvip)); } - tpl_printf(vars, TPLADD, "NICE", "%d", cfg.nice); - tpl_printf(vars, TPLADD, "BINDWAIT", "%d", cfg.bindwait); - - tpl_printf(vars, TPLADD, "TMP", "NETPRIO%d", cfg.netprio); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - - tpl_printf(vars, TPLADD, "PIDFILE", "%s", ESTR(cfg.pidfile)); - - - if(cfg.usrfile != NULL) { tpl_addVar(vars, TPLADD, "USERFILE", cfg.usrfile); } - if(cfg.disableuserfile == 0) { tpl_addVar(vars, TPLADD, "DISABLEUSERFILECHECKED", "checked"); } - if(cfg.usrfileflag == 1) { tpl_addVar(vars, TPLADD, "USERFILEFLAGCHECKED", "selected"); } - if(cfg.mailfile != NULL) { tpl_addVar(vars, TPLADD, "MAILFILE", cfg.mailfile); } - if(cfg.disablemail == 0) { tpl_addVar(vars, TPLADD, "DISABLEMAILCHECKED", "checked"); } - - char *value = mk_t_logfile(); - tpl_addVar(vars, TPLADD, "LOGFILE", value); - free_mk_t(value); - if(cfg.disablelog == 0) { tpl_addVar(vars, TPLADD, "DISABLELOGCHECKED", "checked"); } - tpl_printf(vars, TPLADD, "MAXLOGSIZE", "%d", cfg.max_log_size); - - tpl_addVar(vars, TPLADD, "LOGDUPSCHECKED", (cfg.logduplicatelines == 1) ? "checked" : ""); - tpl_printf(vars, TPLADD, "INITIALDEBUGLEVEL", "%u", cfg.initial_debuglevel); - - if(cfg.cwlogdir != NULL) { tpl_addVar(vars, TPLADD, "CWLOGDIR", cfg.cwlogdir); } - if(cfg.emmlogdir != NULL) { tpl_addVar(vars, TPLADD, "EMMLOGDIR", cfg.emmlogdir); } - tpl_addVar(vars, TPLADD, "ECMFMT", cfg.ecmfmt); - tpl_printf(vars, TPLADD, "LOGHISTORYLINES", "%u", cfg.loghistorylines); - if(cfg.sysloghost != NULL) { tpl_addVar(vars, TPLADD, "SYSLOGHOST", cfg.sysloghost); } - tpl_printf(vars, TPLADD, "SYSLOGPORT", "%u", cfg.syslogport); - - - tpl_printf(vars, TPLADD, "CLIENTTIMEOUT", "%u", cfg.ctimeout); - value = mk_t_caidvaluetab(&cfg.ctimeouttab); - tpl_addVar(vars, TPLADD, "CLIENTTIMEOUT_PERCAID", value); - free_mk_t(value); - tpl_printf(vars, TPLADD, "FALLBACKTIMEOUT", "%u", cfg.ftimeout); - tpl_printf(vars, TPLADD, "CLIENTMAXIDLE", "%u", cfg.cmaxidle); - - - value = mk_t_caidvaluetab(&cfg.ftimeouttab); - tpl_addVar(vars, TPLADD, "FALLBACKTIMEOUT_PERCAID", value); - free_mk_t(value); - - tpl_printf(vars, TPLADD, "SLEEP", "%d", cfg.tosleep); - tpl_addVar(vars, TPLADD, "UNLOCKPARENTALCHECKED", (cfg.ulparent == 1) ? "checked" : ""); - - if(cfg.reload_useraccounts) { tpl_addVar(vars, TPLADD, "RELOADUSERACCOUNTSCHECKED", "checked"); } - if(cfg.reload_readers) { tpl_addVar(vars, TPLADD, "RELOADREADERSCHECKED", "checked"); } - if(cfg.reload_provid) { tpl_addVar(vars, TPLADD, "RELOADPROVIDCHECKED", "checked"); } - if(cfg.reload_services_ids) { tpl_addVar(vars, TPLADD, "RELOADSERVICESIDSCHECKED", "checked"); } - if(cfg.reload_tier_ids) { tpl_addVar(vars, TPLADD, "RELOADTIERUDSCHECKED", "checked"); } - if(cfg.reload_fakecws) { tpl_addVar(vars, TPLADD, "RELOADFAKECWSCHECKED", "checked"); } - if(cfg.reload_ac_stat) { tpl_addVar(vars, TPLADD, "RELOADACSTATCHECKED", "checked"); } - if(cfg.reload_log) { tpl_addVar(vars, TPLADD, "RELOADLOGCHECKED", "checked"); } - - if(cfg.block_same_ip) { tpl_addVar(vars, TPLADD, "BLOCKSAMEIPCHECKED", "checked"); } - if(cfg.block_same_name) { tpl_addVar(vars, TPLADD, "BLOCKSAMENAMECHECKED", "checked"); } - - if(cfg.waitforcards == 1) { tpl_addVar(vars, TPLADD, "WAITFORCARDSCHECKED", "checked"); } - tpl_printf(vars, TPLADD, "EXTRADELAY", "%d", cfg.waitforcards_extra_delay); - if(cfg.preferlocalcards == 1) - { - tpl_addVar(vars, TPLADD, "PREFERCACHEEX", "selected"); - } - else if(cfg.preferlocalcards == 2) - { - tpl_addVar(vars, TPLADD, "PREFERLOCALCARDS", "selected"); - } - - if(cfg.c35_suppresscmd08) - { tpl_addVar(vars, TPLADD, "SUPPRESSCMD08", "checked"); } - - if(cfg.getblockemmauprovid > 0) - { - tpl_addVar(vars, TPLADD, "GETBLOCKEMMAUPROVID", "checked"); - } - - if(cfg.reader_restart_seconds) - { tpl_printf(vars, TPLADD, "READERRESTARTSECONDS", "%d", cfg.reader_restart_seconds); } - - tpl_addVar(vars, TPLADD, "DROPDUPSCHECKED", (cfg.dropdups == 1) ? "checked" : ""); - - if(cfg.resolve_gethostbyname == 1) - { tpl_addVar(vars, TPLADD, "RESOLVER1", "selected"); } - else - { tpl_addVar(vars, TPLADD, "RESOLVER0", "selected"); } - - tpl_printf(vars, TPLADD, "FAILBANTIME", "%d", cfg.failbantime); - tpl_printf(vars, TPLADD, "FAILBANCOUNT", "%d", cfg.failbancount); - - tpl_addVar(vars, TPLADD, "DCHECKCSELECTED", (cfg.double_check == 1) ? "checked" : ""); - - value = mk_t_ftab(&cfg.double_check_caid); - tpl_addVar(vars, TPLADD, "DOUBLECHECKCAID", value); - free_mk_t(value); - - tpl_addVar(vars, TPLADD, "DISABLECRCCWSCHECKEDGLOBAL", (cfg.disablecrccws == 1) ? "checked" : ""); - - value = mk_t_ftab(&cfg.disablecrccws_only_for); - tpl_addVar(vars, TPLADD, "IGNCHKSUMONLYFORGLOBAL", value); - free_mk_t(value); - - tpl_addVar(vars, TPLADD, "CWVOTEENABLEDCHECKED", (cfg.cwvote_enabled == 1) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "CWVOTELOGENABLEDCHECKED", (cfg.cwvote_log_enabled == 1) ? "checked" : ""); - tpl_printf(vars, TPLADD, "CWVOTETIMEOUT", "%d", cfg.cwvote_timeout); - tpl_printf(vars, TPLADD, "CWVOTEMINVOTES", "%d", cfg.cwvote_min_votes); - tpl_printf(vars, TPLADD, "CWVOTELOCALWEIGHT", "%.1f", cfg.cwvote_local_weight); - tpl_printf(vars, TPLADD, "CWVOTEMAXCANDIDATES", "%d", cfg.cwvote_max_candidates); - tpl_addVar(vars, TPLADD, "CWVOTECOMPARE8", (cfg.cwvote_compare_len == 8) ? "selected" : ""); - tpl_addVar(vars, TPLADD, "CWVOTECOMPARE16", (cfg.cwvote_compare_len == 16) ? "selected" : ""); - tpl_addVar(vars, TPLADD, "CWVOTEFALLBACK0", (cfg.cwvote_fallback == 0) ? "selected" : ""); - tpl_addVar(vars, TPLADD, "CWVOTEFALLBACK1", (cfg.cwvote_fallback == 1) ? "selected" : ""); - tpl_addVar(vars, TPLADD, "CWVOTEFALLBACK2", (cfg.cwvote_fallback == 2) ? "selected" : ""); - value = mk_t_cwvote_caidtab(&cfg.cwvote_caids); - tpl_addVar(vars, TPLADD, "CWVOTECAIDS", value); - free_mk_t(value); -#ifdef CS_CACHEEX_AIO - tpl_addVar(vars, TPLADD, "CACHEEXSRCNAME", (cfg.cacheex_srcname_webif == 1) ? "checked" : ""); -#endif - -#ifdef LEDSUPPORT - if(cfg.enableled == 1) - { tpl_addVar(vars, TPLADD, "ENABLELEDSELECTED1", "selected"); } - else if(cfg.enableled == 2) - { tpl_addVar(vars, TPLADD, "ENABLELEDSELECTED2", "selected"); } -#endif - - return tpl_getTpl(vars, "CONFIGGLOBAL"); -} - -#ifdef WITH_LB -static char *send_oscam_config_loadbalancer(struct templatevars *vars, struct uriparams *params) -{ - setActiveSubMenu(vars, MNU_CFG_LOADBAL); - - if(cs_strlen(getParam(params, "button")) > 0) - { - if(cfg.http_readonly) - { - tpl_addMsg(vars, "WebIf is in readonly mode. No changes are possible!"); - } - else - { - if(strcmp(getParam(params, "button"), "Load Stats") == 0) - { - clear_all_stat(); - load_stat_from_file(); - tpl_addMsg(vars, "Stats loaded from file"); - } - - if(strcmp(getParam(params, "button"), "Save Stats") == 0) - { - save_stat_to_file(1); - tpl_addMsg(vars, "Stats saved to file"); - } - - if(strcmp(getParam(params, "button"), "Clear Stats") == 0) - { - clear_all_stat(); - tpl_addMsg(vars, "Stats cleared completly"); - } - - if(strcmp(getParam(params, "button"), "Clear Timeouts") == 0) - { - clean_all_stats_by_rc(E_TIMEOUT, 0); - tpl_addMsg(vars, "Timeout cleared from Stats"); - } - - if(strcmp(getParam(params, "button"), "Clear Not Found") == 0) - { - clean_all_stats_by_rc(E_NOTFOUND, 0); - tpl_addMsg(vars, "Not Found cleared from Stats"); - } - - if(strcmp(getParam(params, "button"), "Clear Invalid") == 0) - { - clean_all_stats_by_rc(E_INVALID, 0); - tpl_addMsg(vars, "Invalid cleared from Stats"); - } - } - } - - webif_save_config("global", vars, params); - - tpl_printf(vars, TPLADD, "TMP", "LBMODE%d", cfg.lb_mode); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - - tpl_printf(vars, TPLADD, "LBSAVE", "%d", cfg.lb_save); - if(cfg.lb_savepath) { tpl_addVar(vars, TPLADD, "LBSAVEPATH", cfg.lb_savepath); } - - tpl_printf(vars, TPLADD, "LBNBESTREADERS", "%d", cfg.lb_nbest_readers); - char *value = mk_t_caidvaluetab(&cfg.lb_nbest_readers_tab); - tpl_addVar(vars, TPLADD, "LBNBESTPERCAID", value); - free_mk_t(value); - tpl_printf(vars, TPLADD, "LBNFBREADERS", "%d", cfg.lb_nfb_readers); - tpl_printf(vars, TPLADD, "LBMAXREADERS", "%d", cfg.lb_max_readers); - tpl_printf(vars, TPLADD, "LBMINECMCOUNT", "%d", cfg.lb_min_ecmcount); - tpl_printf(vars, TPLADD, "LBMAXECEMCOUNT", "%d", cfg.lb_max_ecmcount); - tpl_printf(vars, TPLADD, "LBRETRYLIMIT", "%d", cfg.lb_retrylimit); - - value = mk_t_caidvaluetab(&cfg.lb_retrylimittab); - tpl_addVar(vars, TPLADD, "LBRETRYLIMITS", value); - free_mk_t(value); - - tpl_printf(vars, TPLADD, "LBREOPENSECONDS", "%d", cfg.lb_reopen_seconds); - tpl_printf(vars, TPLADD, "LBCLEANUP", "%d", cfg.lb_stat_cleanup); - - tpl_addVar(vars, TPLADD, "LBREOPENINVALID", (cfg.lb_reopen_invalid == 1) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "LBFORCEALWAYS", (cfg.lb_force_reopen_always == 1) ? "checked" : ""); - - value = mk_t_caidtab(&cfg.lb_noproviderforcaid); - tpl_addVar(vars, TPLADD, "LBNOPROVIDERFORCAID", value); - free_mk_t(value); - - tpl_addVar(vars, TPLADD, "LBAUTOBETATUNNEL", (cfg.lb_auto_betatunnel == 1) ? "checked" : ""); - - if(cfg.lb_auto_betatunnel_mode) - { - tpl_printf(vars, TPLADD, "TMP", "LBAUTOBETATUNNELMODE%d", cfg.lb_auto_betatunnel_mode); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - } - - tpl_printf(vars, TPLADD, "LBPREFERBETA", "%d", cfg.lb_auto_betatunnel_prefer_beta); - - tpl_addVar(vars, TPLADD, "LBAUTOTIMEOUT", (cfg.lb_auto_timeout == 1) ? "checked" : ""); - - tpl_printf(vars, TPLADD, "LBAUTOTIMEOUTP", "%d", cfg.lb_auto_timeout_p); - tpl_printf(vars, TPLADD, "LBAUTOTIMEOUTT", "%d", cfg.lb_auto_timeout_t); - - tpl_addVar(vars, TPLADDONCE, "CONFIG_CONTROL", tpl_getTpl(vars, "CONFIGLOADBALANCERCTRL")); - - return tpl_getTpl(vars, "CONFIGLOADBALANCER"); -} -#endif - -#ifdef MODULE_CAMD33 -static char *send_oscam_config_camd33(struct templatevars *vars, struct uriparams *params) -{ - int32_t i; - - setActiveSubMenu(vars, MNU_CFG_CAMD33); - - webif_save_config("camd33", vars, params); - - if(cfg.c33_port) - { - tpl_printf(vars, TPLADD, "PORT", "%d", cfg.c33_port); - if(IP_ISSET(cfg.c33_srvip)) { tpl_addVar(vars, TPLADD, "SERVERIP", cs_inet_ntoa(cfg.c33_srvip)); } - tpl_addVar(vars, TPLADD, "PASSIVECHECKED", (cfg.c33_passive == 1) ? "checked" : ""); - - for(i = 0; i < (int) sizeof(cfg.c33_key); ++i) { tpl_printf(vars, TPLAPPEND, "KEY", "%02X", cfg.c33_key[i]); } - char *value = mk_t_iprange(cfg.c33_plain); - tpl_addVar(vars, TPLADD, "NOCRYPT", value); - free_mk_t(value); - } - - return tpl_getTpl(vars, "CONFIGCAMD33"); -} -#endif - -#ifdef MODULE_CAMD35 -static char *send_oscam_config_camd35(struct templatevars *vars, struct uriparams *params) -{ - setActiveSubMenu(vars, MNU_CFG_CAMD35); - - webif_save_config("cs357x", vars, params); - - if(cfg.c35_port) - { - tpl_printf(vars, TPLADD, "PORT", "%d", cfg.c35_port); - if(IP_ISSET(cfg.c35_srvip)) - { tpl_addVar(vars, TPLAPPEND, "SERVERIP", cs_inet_ntoa(cfg.c35_srvip)); } - - if(cfg.c35_udp_suppresscmd08) - { tpl_addVar(vars, TPLADD, "SUPPRESSCMD08UDP", "checked"); } - - } - return tpl_getTpl(vars, "CONFIGCAMD35"); -} -#endif - -#ifdef MODULE_CAMD35_TCP -static char *send_oscam_config_camd35tcp(struct templatevars *vars, struct uriparams *params) -{ - setActiveSubMenu(vars, MNU_CFG_CAMD35TCP); - - webif_save_config("cs378x", vars, params); - - if((cfg.c35_tcp_ptab.nports > 0) && (cfg.c35_tcp_ptab.ports[0].s_port > 0)) - { - - char *value = mk_t_camd35tcp_port(); - tpl_addVar(vars, TPLADD, "PORT", value); - free_mk_t(value); - - if(IP_ISSET(cfg.c35_tcp_srvip)) - { tpl_addVar(vars, TPLAPPEND, "SERVERIP", cs_inet_ntoa(cfg.c35_tcp_srvip)); } - - if(cfg.c35_tcp_suppresscmd08) - { tpl_addVar(vars, TPLADD, "SUPPRESSCMD08TCP", "checked"); } - } - return tpl_getTpl(vars, "CONFIGCAMD35TCP"); -} -#endif - -static char *send_oscam_config_cache(struct templatevars *vars, struct uriparams *params) -{ - setActiveSubMenu(vars, MNU_CFG_CACHE); - - webif_save_config("cache", vars, params); - - tpl_printf(vars, TPLADD, "CACHEDELAY", "%u", cfg.delay); - - tpl_printf(vars, TPLADD, "MAXCACHETIME", "%d", cfg.max_cache_time); - -#ifdef CS_CACHEEX - char *value = NULL; - -#ifdef CS_CACHEEX_AIO - value = mk_t_cacheex_cwcheck_valuetab(&cfg.cw_cache_settings); - tpl_addVar(vars, TPLADD, "CWCACHESETTINGS", value); - free_mk_t(value); - - tpl_printf(vars, TPLADD, "CWCACHESIZE", "%d", cfg.cw_cache_size); - - tpl_printf(vars, TPLADD, "CWCACHEMEMORY", "%d", cfg.cw_cache_memory); - - tpl_printf(vars, TPLADD, "ECMCACHESIZE", "%d", cfg.ecm_cache_size); - - tpl_printf(vars, TPLADD, "ECMCACHEMEMORY", "%d", cfg.ecm_cache_memory); - - tpl_printf(vars, TPLADD, "ECMDROPTIME", "%d", cfg.ecm_cache_droptime); -#endif - - value = mk_t_cacheex_valuetab(&cfg.cacheex_wait_timetab); - tpl_addVar(vars, TPLADD, "WAIT_TIME", value); - free_mk_t(value); - -#ifdef CS_CACHEEX_AIO - tpl_printf(vars, TPLADD, "WAITTIME_BLOCK_START", "%d", cfg.waittime_block_start); - - tpl_printf(vars, TPLADD, "WAITTIME_BLOCK_TIME", "%d", cfg.waittime_block_time); -#endif - - value = mk_t_caidvaluetab(&cfg.cacheex_mode1_delay_tab); - tpl_addVar(vars, TPLADD, "CACHEEXMODE1DELAY", value); - free_mk_t(value); - -#ifdef CS_CACHEEX_AIO - value = mk_t_caidvaluetab(&cfg.cacheex_nopushafter_tab); - tpl_addVar(vars, TPLADD, "CACHEEXNOPUSHAFTER", value); - free_mk_t(value); -#endif - - tpl_printf(vars, TPLADD, "MAX_HIT_TIME", "%d", cfg.max_hitcache_time); - - tpl_addVar(vars, TPLADD, "CACHEEXSTATSSELECTED", (cfg.cacheex_enable_stats == 1) ? "checked" : ""); - - tpl_addVar(vars, TPLADD, "WTTCHECKED", (cfg.wait_until_ctimeout == 1) ? "checked" : ""); - -#ifdef CS_CACHEEX_AIO - tpl_addVar(vars, TPLADD, "CACHEEXDROPDIFFS", (cfg.cacheex_dropdiffs == 1) ? "checked" : ""); - - value = mk_t_group(cfg.cacheex_push_lg_groups); - tpl_addVar(vars, TPLADD, "CACHEEXPUSHLGGRPS", value); - free_mk_t(value); - - tpl_addVar(vars, TPLADD, "LGONLYREMOTESETTINGSCHECKED", (cfg.cacheex_lg_only_remote_settings == 1) ? "checked" : ""); - - tpl_addVar(vars, TPLADD, "LOCALGENERATEDONLYCHECKED", (cfg.cacheex_localgenerated_only == 1) ? "checked" : ""); - - value = mk_t_ftab(&cfg.cacheex_lg_only_tab); - tpl_addVar(vars, TPLADD, "LGONLYTAB", value); - free_mk_t(value); - - tpl_addVar(vars, TPLADD, "LOCALGENERATEDONLYINCHECKED", (cfg.cacheex_localgenerated_only_in == 1) ? "checked" : ""); - - tpl_addVar(vars, TPLADD, "LGONLYINAIOONLYCHECKED", (cfg.cacheex_lg_only_in_aio_only == 1) ? "checked" : ""); - - value = mk_t_ftab(&cfg.cacheex_lg_only_in_tab); - tpl_addVar(vars, TPLADD, "LGONLYINTAB", value); - free_mk_t(value); - - value = mk_t_cacheex_hitvaluetab(&cfg.cacheex_filter_caidtab); - tpl_addVar(vars, TPLADD, "CACHEEXECMFILTER", value); - free_mk_t(value); - - value = mk_t_cacheex_hitvaluetab(&cfg.cacheex_filter_caidtab_aio); - tpl_addVar(vars, TPLADD, "CACHEEXECMFILTERAIO", value); - free_mk_t(value); -#endif - - if(cfg.csp_port) - { tpl_printf(vars, TPLADD, "PORT", "%d", cfg.csp_port); } - - if(IP_ISSET(cfg.csp_srvip)) - { tpl_addVar(vars, TPLAPPEND, "SERVERIP", cs_inet_ntoa(cfg.csp_srvip)); } - - value = mk_t_cacheex_hitvaluetab(&cfg.csp.filter_caidtab); - tpl_addVar(vars, TPLADD, "CSP_ECM_FILTER", value); - free_mk_t(value); - - value = mk_t_cacheex_cwcheck_valuetab(&cfg.cacheex_cwcheck_tab); - tpl_addVar(vars, TPLADD, "CACHEEXCWCHECK", value); - free_mk_t(value); - - tpl_addVar(vars, TPLADD, "ARCHECKED", (cfg.csp.allow_request == 1) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "ARFCHECKED", (cfg.csp.allow_reforward == 1) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "BLOCKFAKECWSCHECKED", (cfg.csp.block_fakecws == 1) ? "checked" : ""); -#endif - -#ifdef CW_CYCLE_CHECK -#ifndef CS_CACHEEX - char *value = NULL; -#endif - - tpl_addVar(vars, TPLADD, "CWCYCLECHECK", (cfg.cwcycle_check_enable == 1) ? "checked" : ""); - - value = mk_t_caidtab(&cfg.cwcycle_check_caidtab); - tpl_addVar(vars, TPLADD, "CWCYCLECHECKCAID", value); - free_mk_t(value); - - tpl_printf(vars, TPLADD, "MAXCYCLELIST", "%d", cfg.maxcyclelist); - tpl_printf(vars, TPLADD, "KEEPCYCLETIME", "%d", cfg.keepcycletime); - - if(cfg.onbadcycle) - { - tpl_printf(vars, TPLADD, "TMP", "ONBADCYCLE%d", cfg.onbadcycle); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - } - - tpl_addVar(vars, TPLADD, "DROPOLD", (cfg.cwcycle_dropold == 1) ? "checked" : ""); - - if(cfg.cwcycle_sensitive) - { - tpl_printf(vars, TPLADD, "TMP", "CWCSEN%d", cfg.cwcycle_sensitive); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - } - - tpl_addVar(vars, TPLADD, "ALLOWBADFROMFFB", (cfg.cwcycle_allowbadfromffb == 1) ? "checked" : ""); - - tpl_addVar(vars, TPLADD, "USECWCFROMCE", (cfg.cwcycle_usecwcfromce == 1) ? "checked" : ""); - - -#endif - -#ifdef CS_CACHEEX_AIO - return tpl_getTpl(vars, "CONFIGCACHEAIO"); -#else - return tpl_getTpl(vars, "CONFIGCACHE"); -#endif -} - -#ifdef MODULE_NEWCAMD -static char *send_oscam_config_newcamd(struct templatevars *vars, struct uriparams *params) -{ - int32_t i; - - setActiveSubMenu(vars, MNU_CFG_NEWCAMD); - - webif_save_config("newcamd", vars, params); - - if((cfg.ncd_ptab.nports > 0) && (cfg.ncd_ptab.ports[0].s_port > 0)) - { - - char *value = mk_t_newcamd_port(); - tpl_addVar(vars, TPLADD, "PORT", value); - free_mk_t(value); - - if(IP_ISSET(cfg.ncd_srvip)) - { tpl_addVar(vars, TPLADD, "SERVERIP", cs_inet_ntoa(cfg.ncd_srvip)); } - - for(i = 0; i < (int32_t)sizeof(cfg.ncd_key); i++) - { tpl_printf(vars, TPLAPPEND, "KEY", "%02X", cfg.ncd_key[i]); } - - value = mk_t_iprange(cfg.ncd_allowed); - tpl_addVar(vars, TPLADD, "ALLOWED", value); - free_mk_t(value); - - if(cfg.ncd_keepalive) - { tpl_addVar(vars, TPLADD, "KEEPALIVE", "checked"); } - if(cfg.ncd_mgclient) - { tpl_addVar(vars, TPLADD, "MGCLIENTCHK", "checked"); } - } - return tpl_getTpl(vars, "CONFIGNEWCAMD"); -} -#endif - -#ifdef MODULE_GBOX -static char *send_oscam_config_gbox(struct templatevars *vars, struct uriparams *params) -{ - uint8_t i=0; - char local_gbox_save_gsms[2],local_gbox_msg_type[3], local_gbox_dest_peers[GBOX_MAX_DEST_PEERS*5], tmp_gbox_dest_peers[GBOX_MAX_DEST_PEERS*5] ; - int n=0, len_gbox_save_gsms=0, len_gbox_msg_type=0, len_gbox_dest_peers=0, len_gbox_msg_txt=0; - char *ptr1, *saveptr1, *isbroadcast = NULL; - const char *s; - uint16_t gbox_dest_peers_tmp; - - setActiveSubMenu(vars, MNU_CFG_GBOX); - webif_save_config("gbox", vars, params); - /* - * Action when GetOnlinePeers is pressed - */ - if(streq(getParam(params, "action"), "Online peers")) - { - gbox_get_online_peers(); - // init var - len_gbox_save_gsms=cs_strlen(getParam(params, "gbox_msg_type")); - len_gbox_msg_type=cs_strlen(getParam(params, "gbox_msg_type")); - len_gbox_msg_txt=cs_strlen(getParam(params, "gbox_msg_txt")); - if(len_gbox_msg_txt>GBOX_MAX_MSG_TXT) { len_gbox_msg_txt=GBOX_MAX_MSG_TXT; } - // retrieve value from Webif - cs_strncpy(local_gbox_save_gsms, getParam(params, "gbox_save_gsms"), len_gbox_save_gsms+1); - cfg.gbox_save_gsms=atoi(local_gbox_save_gsms); - cs_strncpy(local_gbox_msg_type, getParam(params, "gbox_msg_type"), len_gbox_msg_type+1); - cfg.gbox_msg_type=atoi(local_gbox_msg_type); - cs_strncpy(cfg.gbox_msg_txt,getParam(params, "gbox_msg_txt"), len_gbox_msg_txt+1); - } - /* - * Action when ResetGSMS button is pressed - */ - if(streq(getParam(params, "action"), "resetallgsms")) - { - cfg.gbox_save_gsms = 0; - cfg.gbox_msg_type = 0; - for(i = 0; i < GBOX_MAX_DEST_PEERS; i++) - { - cfg.gbox_dest_peers[i]='\0'; - } - cfg.gbox_dest_peers_num=0; - for(i = 0; i < GBOX_MAX_MSG_TXT; i++) - { - cfg.gbox_msg_txt[i]='\0'; - } - tpl_addMsg(vars, "GBOX: Reset GSMS datas done!"); - } - /* - * Action when Send GSMS is pressed - */ - if(streq(getParam(params, "action"), "Send GSMS")) - { - // init var - len_gbox_msg_type=cs_strlen(getParam(params, "gbox_msg_type")); - len_gbox_dest_peers=cs_strlen(trim(getParam(params, "gbox_dest_peers"))); - len_gbox_msg_txt=cs_strlen(getParam(params, "gbox_msg_txt")); - if(len_gbox_msg_txt>GBOX_MAX_MSG_TXT) { len_gbox_msg_txt=GBOX_MAX_MSG_TXT; } - // retrieve value from Webif - cs_strncpy(local_gbox_msg_type, getParam(params, "gbox_msg_type"), len_gbox_msg_type+1); - cfg.gbox_msg_type=atoi(local_gbox_msg_type); - cs_strncpy(local_gbox_dest_peers, strtoupper(trim(getParam(params, "gbox_dest_peers"))), len_gbox_dest_peers+1); - cs_strncpy(tmp_gbox_dest_peers, strtoupper(trim(getParam(params, "gbox_dest_peers"))), len_gbox_dest_peers+1); - cs_strncpy(cfg.gbox_msg_txt,getParam(params, "gbox_msg_txt"), len_gbox_msg_txt+1); - n=0; - for (ptr1 = strtok_r(tmp_gbox_dest_peers, ",", &saveptr1); (ptr1); ptr1 = strtok_r(NULL, ",", &saveptr1)) - { - s=trim(ptr1); - if ((n < GBOX_MAX_DEST_PEERS) && (s[strspn(s, "0123456789abcdefABCDEF")] == 0)) - { cfg.gbox_dest_peers[n++] = a2i(trim(ptr1), cs_strlen(trim(ptr1))); } - } - cfg.gbox_dest_peers_num = n; - /* - Start sending GBox SMS - */ - if((cs_strlen(cfg.gbox_msg_txt) > 5)) - { - isbroadcast=strstr(local_gbox_dest_peers, "FFFF"); - if(isbroadcast == NULL) - { - n =0; - for (i = 0, ptr1 = strtok_r(local_gbox_dest_peers, ",", &saveptr1); (i < 4) && (ptr1); ptr1 = strtok_r(NULL, ",", &saveptr1)) - { - s=ptr1; - if ((n < GBOX_MAX_DEST_PEERS) && (s[strspn(s, "0123456789abcdefABCDEF")] == 0)) - { - gbox_dest_peers_tmp = a2i(ptr1, 4); - if(gbox_direct_send_gsms(gbox_dest_peers_tmp, cfg.gbox_msg_type, cfg.gbox_msg_txt)) { cs_log("GBOX message sent to[%04X] type[%d] text[%s] ", gbox_dest_peers_tmp, cfg.gbox_msg_type, cfg.gbox_msg_txt);} - n++; - } - } - tpl_addMsg(vars, "GBOX Send SMS: individual messages started."); - } - else - { - if(gbox_direct_send_gsms(0xFFFF, cfg.gbox_msg_type, cfg.gbox_msg_txt)) { cs_log("GBOX broadcast message sent type[%d] text[%s] ", cfg.gbox_msg_type, cfg.gbox_msg_txt);} - tpl_addMsg(vars, "GBOX Send SMS: broadcast started."); - } - } - else - { - cs_log("GBox SMS: destination peers or message text not specified or too short"); - tpl_addMsg(vars, "GBOX: Send SMS failed - error in input fields: dest peers or text message."); - } - } - - tpl_addVar(vars, TPLADD, "HOSTNAME", xml_encode(vars, cfg.gbox_hostname)); - char *value0 = mk_t_gbox_port(); - tpl_addVar(vars, TPLAPPEND, "PORT", value0); - free_mk_t(value0); - tpl_printf(vars, TPLADD, "MYGBOXPASSWORD", "%08X", cfg.gbox_password); - tpl_printf(vars, TPLADD, "MYGBOXID", "%04X", gbox_get_local_gbox_id()); - tpl_printf(vars, TPLADD, "GBOXRECONNECT", "%d", cfg.gbox_reconnect); - tpl_printf(vars, TPLADD, "GBOXMYVERS", "%02X", cfg.gbox_my_vers); - tpl_printf(vars, TPLAPPEND, "GBOXMYCPUAPI", "%02X", cfg.gbox_my_cpu_api); -#ifdef MODULE_CCCAM - if(cfg.cc_gbx_reshare_en == 1) { tpl_addVar(vars, TPLADD, "GBOXCCCRESHARE", "checked"); } - tpl_addVar(vars, TPLAPPEND, "CCCDEPENDINGCONFIG", tpl_getTpl(vars, "CCCAMRESHAREBIT")); -#endif - if(cfg.log_hello == 1) { tpl_addVar(vars, TPLADD, "GBOXLOGHELLO", "checked"); } - if(cfg.gsms_dis == 1) { tpl_addVar(vars, TPLADD, "GBOXGSMSDISABLE", "checked"); } - if(cfg.dis_attack_txt == 1) { tpl_addVar(vars, TPLADD, "GBOXDISATTACKTXT", "checked"); } - if(cfg.gbox_tmp_dir != NULL) { tpl_addVar(vars, TPLADD, "GBOXTMPDIR", cfg.gbox_tmp_dir); } - char *value1 = mk_t_gbox_proxy_card(); - tpl_addVar(vars, TPLAPPEND, "GBOXPROXYCARD", value1); - free_mk_t(value1); - char *value2 = mk_t_gbox_ignored_peer(); - tpl_addVar(vars, TPLAPPEND, "GBOXIGNOREDPEER", value2); - free_mk_t(value2); - char *value3 = mk_t_gbox_block_ecm(); - tpl_addVar(vars, TPLAPPEND, "GBOXBLOCKECM", value3); - free_mk_t(value3); - char *value4 = mk_t_accept_remm_peer(); - tpl_addVar(vars, TPLAPPEND, "GBOXACCEPTREMM", value4); - free_mk_t(value4); -/* - * GBOX SMS -*/ - tpl_addVar(vars, TPLADD, "GBOXSAVEGSMS", (cfg.gbox_save_gsms == 1) ? "checked" : ""); - if(cfg.gbox_msg_type == 0) - { - tpl_addVar(vars, TPLADD, "GBOXMSGTYPENORMAL", "selected"); - } - else if(cfg.gbox_msg_type == 1) - { - tpl_addVar(vars, TPLADD, "GBOXMSGTYPEOSD", "selected"); - } - char *gmsg_dest_peers = mk_t_gbox_dest_peers(); - tpl_addVar(vars, TPLADD, "GBOXMSGDESTPEERS", gmsg_dest_peers); - free_mk_t(gmsg_dest_peers); - tpl_addVar(vars, TPLADD, "GBOXMSGTXT", cfg.gbox_msg_txt); - - return tpl_getTpl(vars, "CONFIGGBOX"); -} -#endif - -#ifdef MODULE_RADEGAST -static char *send_oscam_config_radegast(struct templatevars *vars, struct uriparams *params) -{ - setActiveSubMenu(vars, MNU_CFG_RADEGAST); - - webif_save_config("radegast", vars, params); - - tpl_printf(vars, TPLADD, "PORT", "%d", cfg.rad_port); - if(IP_ISSET(cfg.rad_srvip)) - { tpl_addVar(vars, TPLADD, "SERVERIP", cs_inet_ntoa(cfg.rad_srvip)); } - tpl_addVar(vars, TPLADD, "USERNAME", xml_encode(vars, cfg.rad_usr)); - - char *value = mk_t_iprange(cfg.rad_allowed); - tpl_addVar(vars, TPLADD, "ALLOWED", value); - free_mk_t(value); - - return tpl_getTpl(vars, "CONFIGRADEGAST"); -} -#endif - -#ifdef MODULE_SCAM -static char *send_oscam_config_scam(struct templatevars *vars, struct uriparams *params) -{ - setActiveSubMenu(vars, MNU_CFG_SCAM); - - webif_save_config("scam", vars, params); - - tpl_printf(vars, TPLADD, "PORT", "%d", cfg.scam_port); - if(IP_ISSET(cfg.scam_srvip)) - { tpl_addVar(vars, TPLADD, "SERVERIP", cs_inet_ntoa(cfg.scam_srvip)); } - - char *value = mk_t_iprange(cfg.scam_allowed); - tpl_addVar(vars, TPLADD, "ALLOWED", value); - free_mk_t(value); - - return tpl_getTpl(vars, "CONFIGSCAM"); -} -#endif - -#ifdef MODULE_STREAMRELAY -static char *send_oscam_config_streamrelay(struct templatevars *vars, struct uriparams *params) -{ - char *value; - - setActiveSubMenu(vars, MNU_CFG_STREAMRELAY); - - webif_save_config("streamrelay", vars, params); - - tpl_printf(vars, TPLADD, "TMP", "STREAMRELAYENABLEDSELECTED%d", cfg.stream_relay_enabled); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - tpl_printf(vars, TPLADD, "STREAM_RELAY_PORT", "%d", cfg.stream_relay_port); - if(cfg.stream_relay_user) - { tpl_printf(vars, TPLADD, "STREAM_RELAY_USER", "%s", cfg.stream_relay_user); } - value = mk_t_caidtab(&cfg.stream_relay_ctab); - tpl_addVar(vars, TPLADD, "STREAM_RELAY_CTAB", value); - free_mk_t(value); - - tpl_printf(vars, TPLADD, "STREAM_SOURCE_HOST", "%s", cfg.stream_source_host); - tpl_addVar(vars, TPLADD, "STREAM_CLIENT_SOURCE_HOST", (cfg.stream_client_source_host == 1) ? "checked" : ""); - tpl_printf(vars, TPLADD, "STREAM_SOURCE_PORT", "%d", cfg.stream_source_port); - if(cfg.stream_source_auth_user) - { tpl_printf(vars, TPLADD, "STREAM_SOURCE_AUTH_USER", "%s", cfg.stream_source_auth_user); } - if(cfg.stream_source_auth_password) - { tpl_printf(vars, TPLADD, "STREAM_SOURCE_AUTH_PASSWORD", "%s", cfg.stream_source_auth_password); } - - tpl_printf(vars, TPLADD, "STREAM_RELAY_BUFFER_TIME", "%d", cfg.stream_relay_buffer_time); - tpl_printf(vars, TPLADD, "STREAM_RELAY_RECONNECT_COUNT", "%d", cfg.stream_relay_reconnect_count); -#ifdef WITH_EMU - tpl_printf(vars, TPLADD, "TMP", "STREAMEMMENABLEDSELECTED%d", cfg.emu_stream_emm_enabled); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - tpl_printf(vars, TPLADD, "STREAM_ECM_DELAY", "%d", cfg.emu_stream_ecm_delay); -#endif - - tpl_printf(vars, TPLADD, "TMP", "STREAMCONFIGCLIENTSELECTED%d", cfg.stream_display_client); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - tpl_addVar(vars, TPLADD, "STREAM_REUSE_CLIENT", (cfg.stream_reuse_client == 1) ? "checked" : ""); -#ifdef WEBIF - tpl_addVar(vars, TPLADD, "STREAM_HIDE_CLIENT", (cfg.stream_hide_client == 1) ? "checked" : ""); -#endif - - return tpl_getTpl(vars, "CONFIGSTREAMRELAY"); -} -#endif - -#ifdef MODULE_CCCAM -static char *send_oscam_config_cccam(struct templatevars *vars, struct uriparams *params) -{ - - setActiveSubMenu(vars, MNU_CFG_CCCAM); - - if(strcmp(getParam(params, "button"), "Refresh list") == 0) - { - cs_log_dbg(D_TRACE, "Entitlements: Refresh Shares start"); -#ifdef MODULE_CCCSHARE - refresh_shares(); -#endif - cs_log_dbg(D_TRACE, "Entitlements: Refresh Shares finished"); - tpl_addMsg(vars, "Refresh Shares started"); - } - - webif_save_config("cccam", vars, params); - - if(streq(getParam(params, "action"), "execute") && !cfg.http_readonly) - { cc_update_nodeid(); } - - char *value = mk_t_cccam_port(); - tpl_addVar(vars, TPLAPPEND, "PORT", value); - free_mk_t(value); - - if(IP_ISSET(cfg.cc_srvip)) - { tpl_addVar(vars, TPLADD, "SERVERIP", cs_inet_ntoa(cfg.cc_srvip)); } - - tpl_printf(vars, TPLADD, "RESHARE", "%d", cfg.cc_reshare); - - if(!strcmp((char *)cfg.cc_version, "2.0.11")) - { - tpl_addVar(vars, TPLADD, "VERSIONSELECTED0", "selected"); - } - else if(!strcmp((char *)cfg.cc_version, "2.1.1")) - { - tpl_addVar(vars, TPLADD, "VERSIONSELECTED1", "selected"); - } - else if(!strcmp((char *)cfg.cc_version, "2.1.2")) - { - tpl_addVar(vars, TPLADD, "VERSIONSELECTED2", "selected"); - } - else if(!strcmp((char *)cfg.cc_version, "2.1.3")) - { - tpl_addVar(vars, TPLADD, "VERSIONSELECTED3", "selected"); - } - else if(!strcmp((char *)cfg.cc_version, "2.1.4")) - { - tpl_addVar(vars, TPLADD, "VERSIONSELECTED4", "selected"); - } - else if(!strcmp((char *)cfg.cc_version, "2.2.0")) - { - tpl_addVar(vars, TPLADD, "VERSIONSELECTED5", "selected"); - } - else if(!strcmp((char *)cfg.cc_version, "2.2.1")) - { - tpl_addVar(vars, TPLADD, "VERSIONSELECTED6", "selected"); - } - else if(!strcmp((char *)cfg.cc_version, "2.3.0")) - { - tpl_addVar(vars, TPLADD, "VERSIONSELECTED7", "selected"); - } - else if(!strcmp((char *)cfg.cc_version, "2.3.1")) - { - tpl_addVar(vars, TPLADD, "VERSIONSELECTED8", "selected"); - } - else if(!strcmp((char *)cfg.cc_version, "2.3.2")) - { - tpl_addVar(vars, TPLADD, "VERSIONSELECTED9", "selected"); - } - - tpl_printf(vars, TPLADD, "UPDATEINTERVAL", "%d", cfg.cc_update_interval); - tpl_printf(vars, TPLADD, "RECV_TIMEOUT", "%u", cfg.cc_recv_timeout); - - tpl_addVar(vars, TPLADD, "STEALTH", (cfg.cc_stealth == 1) ? "checked" : ""); - - tpl_printf(vars, TPLADD, "NODEID", "%02X%02X%02X%02X%02X%02X%02X%02X", - cfg.cc_fixed_nodeid[0], cfg.cc_fixed_nodeid[1], cfg.cc_fixed_nodeid[2], cfg.cc_fixed_nodeid[3], - cfg.cc_fixed_nodeid[4], cfg.cc_fixed_nodeid[5], cfg.cc_fixed_nodeid[6], cfg.cc_fixed_nodeid[7]); - - tpl_printf(vars, TPLADD, "TMP", "MINIMIZECARDSELECTED%d", cfg.cc_minimize_cards); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - - tpl_printf(vars, TPLADD, "TMP", "RESHAREMODE%d", cfg.cc_reshare_services); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - - tpl_printf(vars, TPLADD, "TMP", "IGNRSHRSELECTED%d", cfg.cc_ignore_reshare); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - - tpl_addVar(vars, TPLADD, "FORWARDORIGINCARD", (cfg.cc_forward_origin_card == 1) ? "checked" : ""); - - tpl_addVar(vars, TPLADD, "KEEPCONNECTED", (cfg.cc_keep_connected == 1) ? "checked" : ""); - - tpl_addVar(vars, TPLADDONCE, "CONFIG_CONTROL", tpl_getTpl(vars, "CONFIGCCCAMCTRL")); - - return tpl_getTpl(vars, "CONFIGCCCAM"); -} -#endif - -static bool is_ext(const char *path, const char *ext) -{ - size_t lenpath = cs_strlen(path); - size_t lenext = cs_strlen(ext); - if(lenext > lenpath) - { return 0; } - return memcmp(path + lenpath - lenext, ext, lenext) == 0; -} - -static char *send_oscam_config_webif(struct templatevars *vars, struct uriparams *params) -{ - int32_t i; - - setActiveSubMenu(vars, MNU_CFG_WEBIF); - - webif_save_config("webif", vars, params); - - tpl_printf(vars, TPLADD, "HTTPPORT", "%s%d", cfg.http_use_ssl ? "+" : "", cfg.http_port); - if(IP_ISSET(cfg.http_srvip)) - { tpl_addVar(vars, TPLAPPEND, "SERVERIP", cs_inet_ntoa(cfg.http_srvip)); } - - tpl_addVar(vars, TPLADD, "HTTPUSER", cfg.http_user); - tpl_addVar(vars, TPLADD, "HTTPPASSWORD", cfg.http_pwd); - tpl_addVar(vars, TPLADD, "HTTPOSCAMLABEL", cfg.http_oscam_label); - - // css style selector - tpl_printf(vars, TPLADD, "CSSOPTIONS", "\t\t\t\t\t\t\n", - !cfg.http_css ? " selected" : ""); - - if(cfg.http_tpl) - { - char path[255]; - tpl_getFilePathInSubdir(cfg.http_tpl, "", "style", ".css", path, 255); - if(file_exists(path)) - tpl_printf(vars, TPLAPPEND, "CSSOPTIONS", "\t\t\t\t\t\t\n", - path, - cfg.http_css && strstr(cfg.http_css, path) ? " selected" : "", - path); - } - - struct dirent **namelist; - int count = scandir(cs_confdir, &namelist, 0, NULL); - - if( count >= 0 ) - { - for( i = 0 ; i < count; i++ ) - { - if(is_ext(namelist[i]->d_name, ".css")) - { - tpl_printf(vars, TPLAPPEND, "CSSOPTIONS", "\t\t\t\t\t\t\n", - cs_confdir, - namelist[i]->d_name, - cfg.http_css && strstr(cfg.http_css, namelist[i]->d_name) ? " selected" : "", - cs_confdir, namelist[i]->d_name); - } - free( namelist[i] ); - } - free(namelist); - } - - if(cfg.http_prepend_embedded_css) - { tpl_addVar(vars, TPLADD, "HTTPPREPENDEMBEDDEDCSS", "checked"); } - - tpl_addVar(vars, TPLADD, "HTTPHELPLANG", cfg.http_help_lang); - tpl_addVar(vars, TPLADD, "HTTPLOCALE", cfg.http_locale); - tpl_printf(vars, TPLADD, "HTTPEMMUCLEAN", "%d", cfg.http_emmu_clean); - tpl_printf(vars, TPLADD, "HTTPEMMSCLEAN", "%d", cfg.http_emms_clean); - tpl_printf(vars, TPLADD, "HTTPEMMGCLEAN", "%d", cfg.http_emmg_clean); - tpl_printf(vars, TPLADD, "HTTPREFRESH", "%d", cfg.http_refresh); - tpl_printf(vars, TPLADD, "HTTPPOLLREFRESH", "%d", cfg.poll_refresh); - tpl_addVar(vars, TPLADD, "HTTPTPL", cfg.http_tpl); - tpl_addVar(vars, TPLADD, "HTTPPICONPATH", cfg.http_piconpath); - tpl_addVar(vars, TPLADD, "HTTPSCRIPT", cfg.http_script); - tpl_addVar(vars, TPLADD, "HTTPJSCRIPT", cfg.http_jscript); -#ifndef WEBIF_JQUERY - tpl_addVar(vars, TPLADD, "HTTPEXTERNJQUERY", cfg.http_extern_jquery); -#endif - tpl_printf(vars, TPLADD, "HTTPPICONSIZE", "%d", cfg.http_picon_size); - - if(cfg.http_hide_idle_clients > 0) { tpl_addVar(vars, TPLADD, "CHECKED", "checked"); } - tpl_addVar(vars, TPLADD, "HTTPHIDETYPE", cfg.http_hide_type); - if(cfg.http_status_log > 0) { tpl_addVar(vars, TPLADD, "SHOWLOGCHECKED", "checked"); } - if(cfg.http_showpicons > 0) { tpl_addVar(vars, TPLADD, "SHOWPICONSCHECKED", "checked"); } - if(cfg.http_showmeminfo > 0) { tpl_addVar(vars, TPLADD, "SHOWMEMINFOCHECKED", "checked"); } - if(cfg.http_showuserinfo > 0) { tpl_addVar(vars, TPLADD, "SHOWUSERINFOCHECKED", "checked"); } - if(cfg.http_showreaderinfo > 0) { tpl_addVar(vars, TPLADD, "SHOWREADERINFOCHECKED", "checked"); } - if(cfg.http_showcacheexinfo > 0) { tpl_addVar(vars, TPLADD, "SHOWCACHEEXINFOCHECKED", "checked"); } - if(cfg.http_showloadinfo > 0) { tpl_addVar(vars, TPLADD, "SHOWLOADINFOCHECKED", "checked"); } - if(cfg.http_showecminfo > 0) { tpl_addVar(vars, TPLADD, "SHOWECMINFOCHECKED", "checked"); } - - char *value = mk_t_iprange(cfg.http_allowed); - tpl_addVar(vars, TPLADD, "HTTPALLOW", value); - free_mk_t(value); - - for(i = 0; i < MAX_HTTP_DYNDNS; i++) - { - if(cfg.http_dyndns[i][0]) - { - tpl_addVar(vars, TPLAPPEND, "HTTPDYNDNS", i > 0 ? "," : ""); - tpl_addVar(vars, TPLAPPEND, "HTTPDYNDNS", (char *)cfg.http_dyndns[i]); - } - } - - tpl_addVar(vars, TPLADD, "HTTPSAVEFULLSELECT", (cfg.http_full_cfg == 1) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "HTTPOVERWRITEBAKFILE", (cfg.http_overwrite_bak_file == 1) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "HTTPREADONLY", (cfg.http_readonly == 1) ? "checked" : ""); - - -#ifdef WITH_SSL - if(cfg.http_cert != NULL) { tpl_addVar(vars, TPLADD, "HTTPCERT", cfg.http_cert); } - tpl_addVar(vars, TPLADD, "HTTPFORCESECUREMODESELECT", (cfg.https_force_secure_mode == 1) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "HTTPAUTOCREATECERTSELECT", (cfg.https_auto_create_cert == 1) ? "checked" : ""); -#endif - -#ifndef WEBIF_JQUERY - tpl_addVar(vars, TPLADDONCE, "CONFIGWEBIFJQUERY", tpl_getTpl(vars, "CONFIGWEBIFJQUERYBIT")); -#endif - - tpl_printf(vars, TPLADD, "AULOW", "%d", cfg.aulow); - tpl_printf(vars, TPLADD, "HIDECLIENTTO", "%d", cfg.hideclient_to); - - return tpl_getTpl(vars, "CONFIGWEBIF"); -} - -#ifdef LCDSUPPORT -static char *send_oscam_config_lcd(struct templatevars *vars, struct uriparams *params) -{ - setActiveSubMenu(vars, MNU_CFG_LCD); - - webif_save_config("lcd", vars, params); - - tpl_addVar(vars, TPLADD, "ENABLELCDSELECTED", (cfg.enablelcd == 1) ? "checked" : ""); - - if(cfg.lcd_output_path != NULL) - { tpl_addVar(vars, TPLADD, "LCDOUTPUTPATH", cfg.lcd_output_path); } - - tpl_addVar(vars, TPLADD, "LCDHIDEIDLE", (cfg.lcd_hide_idle == 1) ? "checked" : ""); - - tpl_printf(vars, TPLADD, "LCDREFRESHINTERVAL", "%d", cfg.lcd_write_intervall); - - return tpl_getTpl(vars, "CONFIGLCD"); -} -#endif - -#ifdef MODULE_MONITOR -static char *send_oscam_config_monitor(struct templatevars *vars, struct uriparams *params) -{ - setActiveSubMenu(vars, MNU_CFG_MONITOR); - - webif_save_config("monitor", vars, params); - - tpl_printf(vars, TPLADD, "MONPORT", "%d", cfg.mon_port); - if(IP_ISSET(cfg.mon_srvip)) - { tpl_addVar(vars, TPLADD, "SERVERIP", cs_inet_ntoa(cfg.mon_srvip)); } - - tpl_printf(vars, TPLADD, "AULOW", "%d", cfg.aulow); - tpl_printf(vars, TPLADD, "HIDECLIENTTO", "%d", cfg.hideclient_to); - - char *value = mk_t_iprange(cfg.mon_allowed); - tpl_addVar(vars, TPLADD, "NOCRYPT", value); - free_mk_t(value); - - //Monlevel selector - tpl_printf(vars, TPLADD, "TMP", "MONSELECTED%d", cfg.mon_level); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - - return tpl_getTpl(vars, "CONFIGMONITOR"); -} -#endif - -#ifdef MODULE_SERIAL -static char *send_oscam_config_serial(struct templatevars *vars, struct uriparams *params) -{ - setActiveSubMenu(vars, MNU_CFG_SERIAL); - - webif_save_config("serial", vars, params); - - if(cfg.ser_device) - { - char sdevice[cs_strlen(cfg.ser_device)]; - cs_strncpy(sdevice, cfg.ser_device, sizeof(sdevice)); - char *ptr, *saveptr1 = NULL; - char delimiter[2]; - delimiter[0] = 1; - delimiter[1] = '\0'; - for(ptr = strtok_r(sdevice, delimiter, &saveptr1); ptr; ptr = strtok_r(NULL, delimiter, &saveptr1)) - { - tpl_addVar(vars, TPLADD, "SERIALDEVICE", xml_encode(vars, ptr)); - tpl_addVar(vars, TPLAPPEND, "DEVICES", tpl_getTpl(vars, "CONFIGSERIALDEVICEBIT")); - } - } - - tpl_addVar(vars, TPLADD, "SERIALDEVICE", ""); - tpl_addVar(vars, TPLAPPEND, "DEVICES", tpl_getTpl(vars, "CONFIGSERIALDEVICEBIT")); - - return tpl_getTpl(vars, "CONFIGSERIAL"); -} -#endif - -#ifdef HAVE_DVBAPI -extern const char *boxdesc[]; - -static char *send_oscam_config_dvbapi(struct templatevars *vars, struct uriparams *params) -{ - int32_t i; - - setActiveSubMenu(vars, MNU_CFG_DVBAPI); - - webif_save_config("dvbapi", vars, params); - - if(cfg.dvbapi_enabled > 0) - { tpl_addVar(vars, TPLADD, "ENABLEDCHECKED", "checked"); } - - if(cfg.dvbapi_au > 0) - { tpl_addVar(vars, TPLADD, "AUCHECKED", "checked"); } - - if(cfg.dvbapi_delayer > 0) - { tpl_printf(vars, TPLADD, "DELAYER", "%d", cfg.dvbapi_delayer); } - - tpl_printf(vars, TPLADD, "BOXTYPE", "\n", cfg.dvbapi_boxtype == 0 ? " selected" : ""); - for(i = 1; i <= BOXTYPES; i++) - { - tpl_printf(vars, TPLAPPEND, "BOXTYPE", "%s\n", cfg.dvbapi_boxtype == i ? " selected" : "", boxdesc[i]); - } - - tpl_addVar(vars, TPLADD, "USERNAME", xml_encode(vars, cfg.dvbapi_usr)); - - //PMT Mode - tpl_printf(vars, TPLADD, "TMP", "PMTMODESELECTED%d", cfg.dvbapi_pmtmode); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - - //Request Mode - tpl_printf(vars, TPLADD, "TMP", "REQMODESELECTED%d", cfg.dvbapi_requestmode); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - - //ecminfo_file - if(cfg.dvbapi_ecminfo_file > 0) - { tpl_addVar(vars, TPLADD, "ECMINFOFILECHECKED", "checked"); } - - //ecminfo_type - tpl_printf(vars, TPLADD, "TMP", "ECMINFOTYPESELECTED%d", cfg.dvbapi_ecminfo_type); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - - //read_sdt - tpl_printf(vars, TPLADD, "TMP", "READSDTSELECTED%d", cfg.dvbapi_read_sdt); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - -#ifdef WITH_EXTENDED_CW - //extended_cw_api - tpl_printf(vars, TPLADD, "TMP", "EXTENDEDCWAPISELECTED%d", cfg.dvbapi_extended_cw_api); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); -#endif - - //write_sdt_prov - if(cfg.dvbapi_write_sdt_prov > 0) - { tpl_addVar(vars, TPLADD, "WRITESDTPROVCHECKED", "checked"); } - -#ifdef MODULE_STREAMRELAY - //demuxer_fix - if(cfg.dvbapi_demuxer_fix > 0) - { tpl_addVar(vars, TPLADD, "DEMUXERFIXCHECKED", "checked"); } -#endif - - //TCP listen port - if(cfg.dvbapi_listenport > 0) - { tpl_printf(vars, TPLADD, "LISTENPORT", "%d", cfg.dvbapi_listenport); } - - if(IP_ISSET(cfg.dvbapi_srvip)) - { tpl_addVar(vars, TPLADD, "SERVERIP", cs_inet_ntoa(cfg.dvbapi_srvip)); } - - return tpl_getTpl(vars, "CONFIGDVBAPI"); -} -#endif - -#ifdef CS_ANTICASC -static char *send_oscam_config_anticasc(struct templatevars *vars, struct uriparams *params) -{ - setActiveSubMenu(vars, MNU_CFG_ANTICASC); - - webif_save_config("anticasc", vars, params); - - if(cfg.ac_enabled > 0) { tpl_addVar(vars, TPLADD, "CHECKED", "checked"); } - tpl_printf(vars, TPLADD, "NUMUSERS", "%d", cfg.ac_users); - tpl_printf(vars, TPLADD, "SAMPLETIME", "%d", cfg.ac_stime); - tpl_printf(vars, TPLADD, "SAMPLES", "%d", cfg.ac_samples); - - tpl_printf(vars, TPLADD, "TMP", "PENALTY%d", cfg.ac_penalty); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - - if(cfg.ac_logfile) - { tpl_addVar(vars, TPLADD, "ACLOGFILE", cfg.ac_logfile); } - tpl_printf(vars, TPLADD, "FAKEDELAY", "%d", cfg.ac_fakedelay); - tpl_printf(vars, TPLADD, "DENYSAMPLES", "%d", cfg.ac_denysamples); - - if(cfg.acosc_enabled == 1) - { tpl_addVar(vars, TPLADD, "ACOSC_CHECKED", "checked"); } - tpl_printf(vars, TPLADD, "ACOSC_MAX_ECMS_PER_MINUTE", "%d", cfg.acosc_max_ecms_per_minute); - tpl_printf(vars, TPLADD, "ACOSC_MAX_ACTIVE_SIDS", "%d", cfg.acosc_max_active_sids); - tpl_printf(vars, TPLADD, "ACOSC_ZAP_LIMIT", "%d", cfg.acosc_zap_limit); - tpl_printf(vars, TPLADD, "TMP", "ACOSC_PENALTY%d", cfg.acosc_penalty); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - tpl_printf(vars, TPLADD, "ACOSC_PENALTY_DURATION", "%d", cfg.acosc_penalty_duration); - tpl_printf(vars, TPLADD, "ACOSC_DELAY", "%d", cfg.acosc_delay); - - return tpl_getTpl(vars, "CONFIGANTICASC"); -} -#endif - -static char *send_oscam_config(struct templatevars *vars, struct uriparams *params) -{ - - setActiveMenu(vars, MNU_CONFIG); - - char *part = getParam(params, "part"); - if(!strcmp(part, "webif")) { return send_oscam_config_webif(vars, params); } -#ifdef MODULE_MONITOR - else if(!strcmp(part, "monitor")) { return send_oscam_config_monitor(vars, params); } -#endif -#ifdef LCDSUPPORT - else if(!strcmp(part, "lcd")) { return send_oscam_config_lcd(vars, params); } -#endif -#ifdef MODULE_CAMD33 - else if(!strcmp(part, "camd33")) { return send_oscam_config_camd33(vars, params); } -#endif -#ifdef MODULE_CAMD35 - else if(!strcmp(part, "camd35")) { return send_oscam_config_camd35(vars, params); } -#endif -#ifdef MODULE_CAMD35_TCP - else if(!strcmp(part, "camd35tcp")) { return send_oscam_config_camd35tcp(vars, params); } -#endif - else if(!strcmp(part, "cache")) { return send_oscam_config_cache(vars, params); } -#ifdef MODULE_NEWCAMD - else if(!strcmp(part, "newcamd")) { return send_oscam_config_newcamd(vars, params); } -#endif -#ifdef MODULE_RADEGAST - else if(!strcmp(part, "radegast")) { return send_oscam_config_radegast(vars, params); } -#endif -#ifdef MODULE_SCAM - else if(!strcmp(part, "scam")) { return send_oscam_config_scam(vars, params); } -#endif -#ifdef MODULE_STREAMRELAY - else if(!strcmp(part, "streamrelay")) { return send_oscam_config_streamrelay(vars, params); } -#endif -#ifdef MODULE_CCCAM - else if(!strcmp(part, "cccam")) { return send_oscam_config_cccam(vars, params); } -#endif -#ifdef MODULE_GBOX - else if(!strcmp(part, "gbox")) { return send_oscam_config_gbox(vars, params); } -#endif -#ifdef HAVE_DVBAPI - else if(!strcmp(part, "dvbapi")) { return send_oscam_config_dvbapi(vars, params); } -#endif -#ifdef CS_ANTICASC - else if(!strcmp(part, "anticasc")) { return send_oscam_config_anticasc(vars, params); } -#endif -#ifdef MODULE_SERIAL - else if(!strcmp(part, "serial")) { return send_oscam_config_serial(vars, params); } -#endif -#ifdef WITH_LB - else if(!strcmp(part, "loadbalancer")) { return send_oscam_config_loadbalancer(vars, params); } -#endif - else { return send_oscam_config_global(vars, params); } -} - -static void inactivate_reader(struct s_reader *rdr) -{ - struct s_client *cl = rdr->client; - if(cl) - { kill_thread(cl); } -} - -static bool picon_exists(char *name) -{ - char picon_name[255], path[255]; - char *tpl_path; - tpl_path = cfg.http_piconpath ? cfg.http_piconpath : cfg.http_tpl; - if(!tpl_path) - { return false; } - snprintf(picon_name, sizeof(picon_name) - 1, "IC_%s", name); - return cs_strlen(tpl_getTplPath(picon_name, tpl_path, path, sizeof(path) - 1)) && file_exists(path); -} - -static void clear_rdr_stats(struct s_reader *rdr) -{ - int i; - for(i = 0; i < 4; i++) - { - rdr->emmerror[i] = 0; - rdr->emmwritten[i] = 0; - rdr->emmskipped[i] = 0; - rdr->emmblocked[i] = 0; - } - rdr->ecmsok = 0; -#ifdef CS_CACHEEX_AIO - rdr->ecmsoklg = 0; -#endif - rdr->ecmsnok = 0; - rdr->ecmstout = 0; - rdr->ecmshealthok = 0; -#ifdef CS_CACHEEX_AIO - rdr->ecmshealthoklg = 0; -#endif - rdr->ecmshealthnok = 0; - rdr->ecmshealthtout = 0; - rdr->ecmsfilteredhead = 0; - rdr->ecmsfilteredlen = 0; -} - -static void clear_all_rdr_stats(void) -{ - struct s_reader *rdr; - LL_ITER itr = ll_iter_create(configured_readers); - while((rdr = ll_iter_next(&itr))) - { - clear_rdr_stats(rdr); - } -} - -static char *send_oscam_reader(struct templatevars *vars, struct uriparams *params, int32_t apicall) -{ - struct s_reader *rdr; - int32_t i; - uint8_t md5tmp[MD5_DIGEST_LENGTH]; - char *status; - - if(!apicall) { setActiveMenu(vars, MNU_READERS); } - if(!apicall) - { - if(strcmp(getParam(params, "action"), "resetallrdrstats") == 0) - { - clear_all_rdr_stats(); - } - } - - tpl_addVar(vars, TPLADD, "READERACTIONCOLS", config_enabled(WITH_LB) ? "6" : "5"); - - if(strcmp(getParam(params, "action"), "resetuserstats") == 0) - { - clear_info_clients_stats(); - } - if(strcmp(getParam(params, "action"), "resetreaderstats") == 0) - { - clear_info_readers_stats(); - } - if(strcmp(getParam(params, "action"), "reloadreaders") == 0) - { - if(!cfg.http_readonly) - { - refresh_oscam(REFR_READERS); - refresh_oscam(REFR_ACCOUNTS); - } - } - if((strcmp(getParam(params, "action"), "disable") == 0) || (strcmp(getParam(params, "action"), "enable") == 0)) - { - if(cfg.http_readonly) - { - tpl_addMsg(vars, "WebIf is in readonly mode. Enabling or disabling readers is not possible!"); - } - else - { - rdr = get_reader_by_label(getParam(params, "label")); - if(rdr) - { - if(strcmp(getParam(params, "action"), "enable") == 0) - { - if(!rdr->enable) - { - rdr->enable = 1; - } - } - else - { - if(rdr->enable) - { - rdr->enable = 0; - } - } - if(rdr->typ != R_GBOX) - { - restart_cardreader(rdr, 1); - } -#ifdef MODULE_GBOX - else - { - restart_gbox_peer(rdr->label, 0, 0); - cs_log("gbox -> you must restart oscam so that setting becomes effective"); - } -#endif - - cs_log("reader %s %s by WebIf", rdr->label, rdr->enable == 1 ? "enabled":"disabled"); - - if(write_server() != 0) { tpl_addMsg(vars, "Write Config failed!"); } - -#ifdef MODULE_GBOX - if(!is_network_reader(rdr) && !rdr->enable) - { - gbx_local_card_stat(LOCALCARDDISABLED, 0); - } -#endif - } - } - } - - if(strcmp(getParam(params, "action"), "delete") == 0) - { - if(cfg.http_readonly) - { - tpl_addMsg(vars, "WebIf is in readonly mode. No deletion will be made!"); - } - else - { - rdr = get_reader_by_label(getParam(params, "label")); - if(rdr) - { - inactivate_reader(rdr); - ll_remove(configured_readers, rdr); - - free_reader(rdr); - - if(write_server() != 0) { tpl_addMsg(vars, "Write Config failed!"); } - } - } - } - - if(strcmp(getParam(params, "action"), "reread") == 0) - { - rdr = get_reader_by_label(getParam(params, "label")); - if(rdr) - { - struct s_client *cl = rdr->client; - //reset the counters - for(i = 0; i < 4; i++) - { - rdr->emmerror[i] = 0; - rdr->emmwritten[i] = 0; - rdr->emmskipped[i] = 0; - rdr->emmblocked[i] = 0; - } - - if(rdr->enable == 1 && cl && cl->typ == 'r') - { - add_job(cl, ACTION_READER_CARDINFO, NULL, 0); - } - } - } - - LL_ITER itr = ll_iter_create(configured_readers); - - if(!apicall) - { - for(i = 0, rdr = ll_iter_next(&itr); rdr && rdr->label[0]; rdr = ll_iter_next(&itr), i++) { ; } - tpl_printf(vars, TPLADD, "NEXTREADER", "Reader-%d", i); //Next Readername - } - - int jsondelimiter = 0; - int existing_insert = 0; - - int32_t total_readers = 0; - int32_t disabled_readers = 0; - int32_t active_readers = 0; - int32_t connected_readers = 0; - - ll_iter_reset(&itr); //going to iterate all configured readers - while((rdr = ll_iter_next(&itr))) - { -#ifdef CS_CACHEEX_AIO - const char *proto = reader_get_type_desc(rdr, 0); -#endif - struct s_client *cl = rdr->client; - if(rdr->label[0] && rdr->typ) - { -#ifdef CS_CACHEEX_AIO - char *new_proto; -#if defined(MODULE_CAMD35) || defined (MODULE_CAMD35_TCP) - if(rdr->cacheex.feature_bitfield || (cl && cl->c35_extmode > 1)) -#else - if(rdr->cacheex.feature_bitfield) -#endif - { - const char *aio_suffix = " (cx-aio)"; - - if(cs_malloc(&new_proto, cs_strlen(proto)+cs_strlen(aio_suffix)+1)) { - if (!cs_strncat(new_proto, (char *)proto, cs_strlen(proto)+cs_strlen(aio_suffix)+1)) { - cs_log("FIXME!"); - } - if (!cs_strncat(new_proto, (char *)aio_suffix, cs_strlen(proto)+cs_strlen(aio_suffix)+1)) { - cs_log("FIXME!"); - } - } - } -#endif - total_readers += 1; - - // used for API and WebIf - tpl_addVar(vars, TPLADD, "READERNAME", xml_encode(vars, rdr->label)); - - MD5((uint8_t *)rdr->label, cs_strlen(rdr->label), md5tmp); - int z; - tpl_addVar(vars, TPLADD, "LABELMD5","id_"); - for (z = 0; z < MD5_DIGEST_LENGTH; z++) - { - tpl_printf(vars, TPLAPPEND, "LABELMD5", "%02x", md5tmp[z]); - } -#ifdef MODULE_GBOX - if(apicall) - { - tpl_addVar(vars, TPLADD, "LASTGSMS", ""); - tpl_addVar(vars, TPLADD, "LASTGSMS", rdr->last_gsms); - } -#endif - if(apicall) - { - tpl_printf(vars, TPLADD, "PICONENABLED", "%d", cfg.http_showpicons?1:0); - } - tpl_addVar(vars, TPLADD, "READERNAMEENC", urlencode(vars, rdr->label)); - if(!existing_insert) - { - tpl_printf(vars, TPLADD, "EXISTING_INS", "'%s'", urlencode(vars, rdr->label)); - existing_insert++; - }else - { - tpl_printf(vars, TPLAPPEND, "EXISTING_INS", ",'%s'", urlencode(vars, rdr->label)); - } - tpl_addVar(vars, TPLADD, "READERCLASS", rdr->enable ? "enabledreader" : "disabledreader"); - - if(rdr->enable) { active_readers += 1; } - else { disabled_readers += 1; } - - if(rdr->tcp_connected) - { - connected_readers += 1; - -#ifdef CS_CACHEEX_AIO - if(rdr->cacheex.feature_bitfield) - { - tpl_addVar(vars, TPLADD, "CLIENTPROTOSORT", (const char*)new_proto); - tpl_addVar(vars, TPLADD, "CLIENTPROTO", (const char*)new_proto); - if(cfg.http_showpicons) - { - char picon_name[32]; - snprintf(picon_name, sizeof(picon_name) / sizeof(char) - 1, "%s", new_proto); - if(picon_exists(picon_name)) - { - tpl_printf(vars, TPLADDONCE, "PROTOICON", "%s",(char*)new_proto); - } - } - - if(rdr->cacheex.feature_bitfield & 32) - tpl_addVar(vars, TPLADD, "CLIENTPROTOTITLE", rdr->cacheex.aio_version); - else if(cl->reader->cacheex.feature_bitfield) - tpl_addVar(vars, TPLADD, "CLIENTPROTOTITLE", "[cx-aio < 9.2.3]"); - } - else - { - tpl_addVar(vars, TPLADD, "CLIENTPROTOSORT", proto); - tpl_addVar(vars, TPLADD, "CLIENTPROTO", proto); - if(cfg.http_showpicons) - { - char picon_name[32]; - snprintf(picon_name, sizeof(picon_name) / sizeof(char) - 1, "%s", proto); - if(picon_exists(picon_name)) - { - tpl_printf(vars, TPLADDONCE, "PROTOICON", "%s",(char *)proto); - } - } - } -#else - tpl_addVar(vars, TPLADD, "CLIENTPROTO", reader_get_type_desc(rdr, 0)); - tpl_addVar(vars, TPLADD, "CLIENTPROTOSORT", reader_get_type_desc(rdr, 0)); - if(cfg.http_showpicons) - { - char picon_name[32]; - snprintf(picon_name, sizeof(picon_name) / sizeof(char) - 1, "%s", reader_get_type_desc(rdr, 0)); - if(picon_exists(picon_name)) - { - tpl_printf(vars, TPLADDONCE, "PROTOICON", "%s", reader_get_type_desc(rdr, 0)); - } - } -#endif - switch(rdr->card_status) - { - case CARD_INSERTED: - status = "online"; - tpl_addVar(vars, TPLADD, "RSTATUS", status); - tpl_addVar(vars, TPLADD, "READERCLASS", "r_connected"); - break; - - case NO_CARD: - case UNKNOWN: - case READER_DEVICE_ERROR: - case CARD_NEED_INIT: - case CARD_FAILURE: - default: - status = "connected"; - tpl_addVar(vars, TPLADD, "RSTATUS", status); - tpl_addVar(vars, TPLADD, "READERCLASS", "r_undefined"); - break; - } - - tpl_addVar(vars, TPLADD, "READERIP", cs_inet_ntoa(rdr->client->ip)); - } - else - { - /* default initial values */ - tpl_addVar(vars, TPLADDONCE, "RSTATUS", "offline"); - tpl_addVar(vars, TPLADDONCE, "READERIP", ""); - tpl_addVar(vars, TPLADDONCE, "CLIENTPROTO", ""); - tpl_addVar(vars, TPLADDONCE, "CLIENTPROTOSORT", ""); - tpl_addVar(vars, TPLADDONCE, "CLIENTPROTOTITLE", ""); - tpl_addVar(vars, TPLADDONCE, "PROTOICON", ""); - - if(!is_network_reader(rdr) && rdr->enable) - { - switch(rdr->card_status) - { - case CARD_INSERTED: - status = "active"; - tpl_addVar(vars, TPLADD, "RSTATUS", status); - tpl_addVar(vars, TPLADD, "READERCLASS", "r_connected"); - break; - - case NO_CARD: - case UNKNOWN: - case READER_DEVICE_ERROR: - case CARD_NEED_INIT: - case CARD_FAILURE: - default: - status = "connected"; - tpl_addVar(vars, TPLADD, "RSTATUS", status); - tpl_addVar(vars, TPLADD, "READERCLASS", "r_undefined"); - break; - } - - tpl_addVar(vars, TPLADD, "CLIENTPROTO", reader_get_type_desc(rdr, 0)); - tpl_addVar(vars, TPLADD, "CLIENTPROTOSORT", reader_get_type_desc(rdr, 0)); - if(cfg.http_showpicons) - { - char picon_name[32]; - snprintf(picon_name, sizeof(picon_name) / sizeof(char) - 1, "%s", reader_get_type_desc(rdr, 0)); - if(picon_exists(picon_name)) - { - tpl_printf(vars, TPLADDONCE, "PROTOICON", "%s", reader_get_type_desc(rdr, 0)); - } - } - } - } - - if(rdr->description) - tpl_printf(vars, TPLADD, "DESCRIPTION","%s(%s)",!apicall?" ":"",xml_encode(vars, rdr->description)); - else - tpl_addVar(vars, TPLADD, "DESCRIPTION", ""); - - if(cfg.http_showpicons && !apicall) - { - tpl_addVar(vars, TPLADD, "READERBIT", tpl_getTpl(vars, picon_exists(xml_encode(vars, rdr->label)) ? "READERNAMEBIT" : "READERNOICON")); -#ifdef CS_CACHEEX_AIO - if(rdr->cacheex.feature_bitfield) - { - tpl_addVar(vars, TPLADD, "CLIENTPROTO", picon_exists(xml_encode(vars, (const char*)new_proto)) ? tpl_getTpl(vars, "READERCTYPBIT") : tpl_getTpl(vars, "READERCTYPNOICON")); - } - else - { -#endif - tpl_addVar(vars, TPLADD, "CLIENTPROTO", picon_exists(xml_encode(vars, reader_get_type_desc(rdr, 0))) ? tpl_getTpl(vars, "READERCTYPBIT") : tpl_getTpl(vars, "READERCTYPNOICON")); -#ifdef CS_CACHEEX_AIO - } -#endif - } - else - tpl_addVar(vars, TPLADD, "READERBIT", tpl_getTpl(vars, "READERLABEL")); - - char *value = mk_t_group(rdr->grp); - tpl_addVar(vars, TPLADD, "GROUPS", value); - free_mk_t(value); - tpl_printf(vars, TPLADD, "EMMERRORUK", PRINTF_LOCAL_D, rdr->emmerror[UNKNOWN]); - tpl_printf(vars, TPLADD, "EMMERRORG", PRINTF_LOCAL_D, rdr->emmerror[GLOBAL]); - tpl_printf(vars, TPLADD, "EMMERRORS", PRINTF_LOCAL_D, rdr->emmerror[SHARED]); - tpl_printf(vars, TPLADD, "EMMERRORUQ", PRINTF_LOCAL_D, rdr->emmerror[UNIQUE]); - - tpl_printf(vars, TPLADD, "EMMWRITTENUK", PRINTF_LOCAL_D, rdr->emmwritten[UNKNOWN]); - tpl_printf(vars, TPLADD, "EMMWRITTENG", PRINTF_LOCAL_D, rdr->emmwritten[GLOBAL]); - tpl_printf(vars, TPLADD, "EMMWRITTENS", PRINTF_LOCAL_D, rdr->emmwritten[SHARED]); - tpl_printf(vars, TPLADD, "EMMWRITTENUQ", PRINTF_LOCAL_D, rdr->emmwritten[UNIQUE]); - - tpl_printf(vars, TPLADD, "EMMSKIPPEDUK", PRINTF_LOCAL_D, rdr->emmskipped[UNKNOWN]); - tpl_printf(vars, TPLADD, "EMMSKIPPEDG", PRINTF_LOCAL_D, rdr->emmskipped[GLOBAL]); - tpl_printf(vars, TPLADD, "EMMSKIPPEDS", PRINTF_LOCAL_D, rdr->emmskipped[SHARED]); - tpl_printf(vars, TPLADD, "EMMSKIPPEDUQ", PRINTF_LOCAL_D, rdr->emmskipped[UNIQUE]); - - tpl_printf(vars, TPLADD, "EMMBLOCKEDUK", PRINTF_LOCAL_D, rdr->emmblocked[UNKNOWN]); - tpl_printf(vars, TPLADD, "EMMBLOCKEDG", PRINTF_LOCAL_D, rdr->emmblocked[GLOBAL]); - tpl_printf(vars, TPLADD, "EMMBLOCKEDS", PRINTF_LOCAL_D, rdr->emmblocked[SHARED]); - tpl_printf(vars, TPLADD, "EMMBLOCKEDUQ", PRINTF_LOCAL_D, rdr->emmblocked[UNIQUE]); - - tpl_printf(vars, TPLADD, "ECMSOK", PRINTF_LOCAL_D, rdr->ecmsok); - tpl_printf(vars, TPLADD, "ECMSOKREL", " (%.2f %%)", rdr->ecmshealthok); -#ifdef CS_CACHEEX_AIO - tpl_printf(vars, TPLADD, "ECMSOKLG", PRINTF_LOCAL_D, rdr->ecmsoklg); - tpl_printf(vars, TPLADD, "ECMSOKLGREL", " (%.2f %%)", rdr->ecmshealthoklg); -#endif - tpl_printf(vars, TPLADD, "ECMSNOK", PRINTF_LOCAL_D, rdr->ecmsnok); - tpl_printf(vars, TPLADD, "ECMSNOKREL", " (%.2f %%)",rdr->ecmshealthnok); - tpl_printf(vars, TPLADD, "ECMSTOUT", PRINTF_LOCAL_D, rdr->ecmstout); - tpl_printf(vars, TPLADD, "ECMSTOUTREL", " (%.2f %%)",rdr->ecmshealthtout); - tpl_printf(vars, TPLADD, "ECMSFILTEREDHEAD", PRINTF_LOCAL_D, rdr->ecmsfilteredhead); - tpl_printf(vars, TPLADD, "ECMSFILTEREDLEN", PRINTF_LOCAL_D, rdr->ecmsfilteredlen); -#ifdef WITH_LB - tpl_printf(vars, TPLADD, "LBWEIGHT", "%d", rdr->lb_weight); -#endif - if(!is_network_reader(rdr)) //reader is physical - { - tpl_addVar(vars, TPLADD, "REFRICO", "image?i=ICREF"); - tpl_addVar(vars, TPLADD, "READERREFRESH", tpl_getTpl(vars, "READERREFRESHBIT")); - tpl_addVar(vars, TPLADD, "ENTICO", "image?i=ICENT"); - tpl_addVar(vars, TPLADD, "ENTITLEMENT", tpl_getTpl(vars, "READERENTITLEBIT")); - } - else - { - tpl_addVar(vars, TPLADD, "READERREFRESH", ""); - if(rdr->typ == R_CCCAM) - { - tpl_addVar(vars, TPLADD, "ENTICO", "image?i=ICENT"); - tpl_addVar(vars, TPLADD, "ENTITLEMENT", tpl_getTpl(vars, "READERENTITLEBIT")); - } - else - { - tpl_addVar(vars, TPLADD, "ENTITLEMENT", ""); - } - } - - if(rdr->enable == 0) - { - tpl_addVar(vars, TPLADD, "SWITCHICO", "image?i=ICENA"); - tpl_addVar(vars, TPLADD, "SWITCHTITLE", "Enable"); - tpl_addVar(vars, TPLADD, "SWITCH", "enable"); - tpl_addVar(vars, TPLADD, "WRITEEMM", ""); - } - else - { - tpl_addVar(vars, TPLADD, "SWITCHICO", "image?i=ICDIS"); - tpl_addVar(vars, TPLADD, "SWITCHTITLE", "Disable"); - tpl_addVar(vars, TPLADD, "SWITCH", "disable"); - - tpl_addVar(vars, TPLADD, "EMMICO", "image?i=ICEMM"); - tpl_addVar(vars, TPLADD, "WRITEEMM", tpl_getTpl(vars, "READERWRITEEMMBIT")); - } - - if(!apicall) - { - // Add to WebIf Template -#ifdef CS_CACHEEX_AIO - tpl_addVar(vars, TPLAPPEND, "READERLIST", tpl_getTpl(vars, "READERSBITAIO")); -#else - tpl_addVar(vars, TPLAPPEND, "READERLIST", tpl_getTpl(vars, "READERSBIT")); -#endif - } - else - { - - // used only for API - tpl_addVar(vars, TPLADD, "APIREADERENABLED", !rdr->enable ? "0" : "1"); - if(cl) - { - tpl_printf(vars, TPLADD, "APIREADERTYPE", "%c", cl->typ ? cl->typ : 'x'); - } - - if(apicall==1) - { - // Add to API Template - tpl_addVar(vars, TPLAPPEND, "APIREADERLIST", tpl_getTpl(vars, "APIREADERSBIT")); - } - if(apicall==2) - { - tpl_printf(vars, TPLAPPEND, "APIREADERLIST","%s%s",jsondelimiter?",":"", tpl_getTpl(vars, "JSONREADERBIT")); - jsondelimiter++; - } - } -#ifdef CS_CACHEEX_AIO - if(rdr->cacheex.feature_bitfield) - { - free(new_proto); - } -#endif - } - } - - tpl_printf(vars, TPLADD, "TOTAL_READERS", "%d", total_readers); - tpl_printf(vars, TPLADD, "TOTAL_DISABLED_READERS", "%d", disabled_readers); - tpl_printf(vars, TPLADD, "TOTAL_ACTIVE_READERS", "%d", active_readers); - tpl_printf(vars, TPLADD, "TOTAL_CONNECTED_READERS", "%d", connected_readers); - - //CM info - tpl_addVar(vars, TPLADD, "DISPLAYUSERINFO", "hidden"); // no userinfo in readers - set_ecm_info(vars); - - if(!apicall) - { -#ifdef MODULE_CAMD33 - tpl_addVar(vars, TPLAPPEND, "ADDPROTOCOL", "\n"); -#endif -#ifdef MODULE_CAMD35 - tpl_addVar(vars, TPLAPPEND, "ADDPROTOCOL", "\n"); -#endif -#ifdef MODULE_CAMD35_TCP - tpl_addVar(vars, TPLAPPEND, "ADDPROTOCOL", "\n"); -#endif -#ifdef MODULE_NEWCAMD - tpl_addVar(vars, TPLAPPEND, "ADDPROTOCOL", "\n"); - tpl_addVar(vars, TPLAPPEND, "ADDPROTOCOL", "\n"); -#endif -#ifdef MODULE_CCCAM - tpl_addVar(vars, TPLAPPEND, "ADDPROTOCOL", "\n"); -#endif -#ifdef MODULE_GBOX - tpl_addVar(vars, TPLAPPEND, "ADDPROTOCOL", "\n"); -#endif -#ifdef MODULE_RADEGAST - tpl_addVar(vars, TPLAPPEND, "ADDPROTOCOL", "\n"); -#endif -#ifdef MODULE_SERIAL - tpl_addVar(vars, TPLAPPEND, "ADDPROTOCOL", "\n"); -#endif -#ifdef MODULE_CONSTCW - tpl_addVar(vars, TPLAPPEND, "ADDPROTOCOL", "\n"); -#endif -#ifdef MODULE_SCAM - tpl_addVar(vars, TPLAPPEND, "ADDPROTOCOL", "\n"); -#endif - - for(i = 0; cardreaders[i]; i++) - { - tpl_printf(vars, TPLAPPEND, "ADDPROTOCOL", "\n", xml_encode(vars, cardreaders[i]->desc)); - } -#ifdef CS_CACHEEX_AIO - return tpl_getTpl(vars, "READERSAIO"); -#else - return tpl_getTpl(vars, "READERS"); -#endif - } - else - { - if(apicall == 1) - { - return tpl_getTpl(vars, "APIREADERS"); - } - else - { - return tpl_getTpl(vars, "JSONREADER"); - } - } -} - -static char *send_oscam_reader_config(struct templatevars *vars, struct uriparams *params) -{ - int32_t i; - int32_t apicall = 0; - char *reader_ = getParam(params, "label"); - char *value; - - struct s_reader *rdr; - - if(!apicall) { setActiveMenu(vars, MNU_READERS); } - - if(strcmp(getParam(params, "action"), "Add") == 0) - { - // Add new reader - struct s_reader *newrdr; - if(!cs_malloc(&newrdr, sizeof(struct s_reader))) { return "0"; } - for(i = 0; i < (*params).paramcount; ++i) - { - if(strcmp((*params).params[i], "action")) - { chk_reader((*params).params[i], (*params).values[i], newrdr); } - } - module_reader_set(newrdr); - reader_ = newrdr->label; - reader_set_defaults(newrdr); - newrdr->enable = 0; // do not start the reader because must configured before - ll_append(configured_readers, newrdr); - tpl_addMsg(vars, "New Reader has been added with default settings"); - } - else if(strcmp(getParam(params, "action"), "Save") == 0) - { - - rdr = get_reader_by_label(getParam(params, "label")); - if(!rdr) - { return NULL; } - //if (is_network_reader(rdr)) - // inactivate_reader(rdr); //Stop reader before reinitialization - char servicelabels[1024] = ""; - char servicelabelslb[1024] = ""; - - for(i = 0; i < (*params).paramcount; ++i) - { - if((strcmp((*params).params[i], "reader")) && (strcmp((*params).params[i], "action"))) - { - if(!strcmp((*params).params[i], "services")) - { snprintf(servicelabels + cs_strlen(servicelabels), sizeof(servicelabels) - cs_strlen(servicelabels), "%s,", (*params).values[i]); } - else if(!strcmp((*params).params[i], "lb_whitelist_services")) - { snprintf(servicelabelslb + cs_strlen(servicelabelslb), sizeof(servicelabelslb) - cs_strlen(servicelabelslb), "%s,", (*params).values[i]); } - else - /*if(cs_strlen((*params).values[i]) > 0)*/ - { chk_reader((*params).params[i], (*params).values[i], rdr); } - } - //printf("param %s value %s\n",(*params).params[i], (*params).values[i]); - } - chk_reader("services", servicelabels, rdr); - chk_reader("lb_whitelist_services", servicelabelslb, rdr); - - if(is_network_reader(rdr) || rdr->typ == R_EMU) //physical readers make trouble if re-started - { - if(rdr) - { - if(rdr->typ != R_GBOX) - { - restart_cardreader(rdr, 1); - } -#ifdef MODULE_GBOX - else - { - //cs_log("SAVE - single gbox reader %s restarted by WebIf", rdr->label); - restart_gbox_peer(rdr->label, 0, 0); - } -#endif - } - } - - if(write_server() != 0) { tpl_addMsg(vars, "Write Config failed!"); } else { tpl_addMsg(vars, "Reader config updated and saved"); } - - } - - rdr = get_reader_by_label(reader_); - if(!rdr) - { return NULL; } - - // Label, Description - tpl_addVar(vars, TPLADD, "READERNAME", xml_encode(vars, rdr->label)); - tpl_addVar(vars, TPLADD, "DESCRIPTION", xml_encode(vars, rdr->description)); - - // enabled - if(!apicall) - { - tpl_addVar(vars, TPLADD, "ENABLED", (rdr->enable == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "ENABLEDVALUE", (rdr->enable == 1) ? "1" : "0"); - } - - tpl_addVar(vars, TPLADD, "PASSWORD", xml_encode(vars, rdr->r_pwd)); - tpl_addVar(vars, TPLADD, "USERNAME", xml_encode(vars, rdr->r_usr)); - tpl_addVar(vars, TPLADD, "PASS", xml_encode(vars, rdr->r_pwd)); - - // Key Newcamd - for(i = 0; i < (int32_t)sizeof(rdr->ncd_key); i++) - { tpl_printf(vars, TPLAPPEND, "NCD_KEY", "%02X", rdr->ncd_key[i]); } - - // Pincode - tpl_addVar(vars, TPLADD, "PINCODE", rdr->pincode); - - // Emmfile Path - if(rdr->emmfile) { tpl_addVar(vars, TPLADD, "EMMFILE", (char *)rdr->emmfile); } - - // Inactivity timeout - tpl_printf(vars, TPLADD, "INACTIVITYTIMEOUT", "%d", rdr->tcp_ito); - - // Receive timeout - tpl_printf(vars, TPLADD, "RECEIVETIMEOUT", "%d", rdr->tcp_rto); - - // keepalive - tpl_addVar(vars, TPLADD, "RDRKEEPALIVE", (rdr->keepalive == 1) ? "checked" : ""); - - // Connect on init (newcamd) - if(!apicall) - { - tpl_addVar(vars, TPLADD, "CONNECTONINITCHECKED", (rdr->ncd_connect_on_init == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "CONNECTONINITCHECKED", (rdr->ncd_connect_on_init == 1) ? "1" : "0"); - } - - // Reset Cycle - tpl_printf(vars, TPLADD, "RESETCYCLE", "%d", rdr->resetcycle); - - // Disable Serverfilter - if(!apicall) - { - tpl_addVar(vars, TPLADD, "DISABLESERVERFILTERCHECKED", (rdr->ncd_disable_server_filt == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "DISABLESERVERFILTERVALUE", (rdr->ncd_disable_server_filt == 1) ? "1" : "0"); - } - -#ifdef MODULE_GHTTP - // Use SSL - if(!apicall) - { - tpl_addVar(vars, TPLADD, "USESSLCHECKED", (rdr->ghttp_use_ssl == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "USESSLVALUE", (rdr->ghttp_use_ssl == 1) ? "1" : "0"); - } -#endif - - // IPv4 force - if (!apicall) - { - tpl_addVar(vars, TPLADD, "IPV4FORCE", (rdr->ipv4force == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "IPV4FORCE", (rdr->ipv4force == 1) ? "1" : "0"); - } - - // Fallback - if(!apicall) - { - tpl_addVar(vars, TPLADD, "FALLBACKCHECKED", (rdr->fallback == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "FALLBACKVALUE", (rdr->fallback == 1) ? "1" : "0"); - } - - // Fallback per caid - value = mk_t_ftab(&rdr->fallback_percaid); - tpl_addVar(vars, TPLADD, "FALLBACK_PERCAID", value); - free_mk_t(value); - - // disable checksum test only for selected caid/provid - value = mk_t_ftab(&rdr->disablecrccws_only_for); - tpl_addVar(vars, TPLADD, "IGN_CHKSUM_ONLYFOR", value); - free_mk_t(value); - -#ifdef WITH_LB - tpl_addVar(vars, TPLADD, "LBFORCEFALLBACK", (rdr->lb_force_fallback == 1) ? "checked" : ""); -#endif - -#ifdef CS_CACHEEX - // Cacheex - if(!apicall) - { - tpl_printf(vars, TPLADD, "TMP", "CACHEEXSELECTED%d", rdr->cacheex.mode); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - } - else - { - tpl_printf(vars, TPLADD, "CACHEEX", "%d", rdr->cacheex.mode); - } - tpl_printf(vars, TPLADD, "CACHEEX_MAXHOP", "%d", rdr->cacheex.maxhop); -#ifdef CS_CACHEEX_AIO - tpl_printf(vars, TPLADD, "CACHEEX_MAXHOP_LG", "%d", rdr->cacheex.maxhop_lg); -#endif - value = mk_t_cacheex_hitvaluetab(&rdr->cacheex.filter_caidtab); - //if (cs_strlen(value) > 0) - tpl_printf(vars, TPLADD, "CACHEEX_ECM_FILTER", "%s", value); - free_mk_t(value); - - tpl_addVar(vars, TPLADD, "DCCHECKED", (rdr->cacheex.drop_csp == 1) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "ARCHECKED", (rdr->cacheex.allow_request == 1) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "AFCHECKED", (rdr->cacheex.allow_filter == 1) ? "checked" : ""); -#ifdef CS_CACHEEX_AIO - tpl_addVar(vars, TPLADD, "AMCHECKED", (rdr->cacheex.allow_maxhop == 1) ? "checked" : ""); -#endif - tpl_addVar(vars, TPLADD, "BLOCKFAKECWSCHECKED", (rdr->cacheex.block_fakecws == 1) ? "checked" : ""); -#ifdef CS_CACHEEX_AIO - tpl_addVar(vars, TPLADD, "USECWCHECKFORPUSHCHECKED", (rdr->cacheex.cw_check_for_push == 1) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "LGONLYREMOTESETTINGSCHECKED", (rdr->cacheex.lg_only_remote_settings == 1) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "LOCALGENERATEDONLYCHECKED", (rdr->cacheex.localgenerated_only == 1) ? "checked" : ""); - - value = mk_t_ftab(&rdr->cacheex.lg_only_tab); - tpl_addVar(vars, TPLADD, "LGONLYTAB", value); - free_mk_t(value); - - tpl_addVar(vars, TPLADD, "LOCALGENERATEDONLYINCHECKED", (rdr->cacheex.localgenerated_only_in == 1) ? "checked" : ""); - - tpl_addVar(vars, TPLADD, "LGONLYINAIOONLYCHECKED", (rdr->cacheex.lg_only_in_aio_only == 1) ? "checked" : ""); - - value = mk_t_ftab(&rdr->cacheex.lg_only_in_tab); - tpl_addVar(vars, TPLADD, "LGONLYINTAB", value); - free_mk_t(value); - - value = mk_t_caidvaluetab(&rdr->cacheex.cacheex_nopushafter_tab); - tpl_addVar(vars, TPLADD, "CACHEEXNOPUSHAFTER", value); - free_mk_t(value); -#endif -#endif - - // BoxID - if(rdr->boxid) - { tpl_printf(vars, TPLADD, "BOXID", "%08X", rdr->boxid); } - -#ifdef READER_VIDEOGUARD - // Filt 07 - if(!apicall) - { - tpl_addVar(vars, TPLADD, "FIX07CHECKED", (rdr->fix_07 == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "FIX07VALUE", (rdr->fix_07 == 1) ? "1" : "0"); - } - - - // Fix 9993 - if(!apicall) - { - tpl_addVar(vars, TPLADD, "FIX9993CHECKED", (rdr->fix_9993 == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "FIX9993VALUE", (rdr->fix_9993 == 1) ? "1" : "0"); - } -#endif - - // Drop CWs with wrong checksum: - if(!apicall) - { - tpl_addVar(vars, TPLADD, "DROPBADCWSCHECKED", (rdr->dropbadcws == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "DROPBADCWSVALUE", (rdr->dropbadcws == 1) ? "1" : "0"); - } - - // Disable CWs checksum test: - if(!apicall) - { - tpl_addVar(vars, TPLADD, "DISABLECRCCWSCHECKED", (rdr->disablecrccws == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "DISABLECRCCWSVALUE", (rdr->disablecrccws == 1) ? "1" : "0"); - } - -#ifdef WITH_CARDREADER - // Set reader to use GPIO - if(!apicall) - { - tpl_addVar(vars, TPLADD, "USE_GPIOCHECKED", rdr->use_gpio ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "USE_GPIOVALUE", rdr->use_gpio ? "1" : "0"); - } -#endif - - // AUdisabled - if(!apicall) - { - tpl_addVar(vars, TPLADD, "AUDISABLED", (rdr->audisabled == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "AUDISABLEDVALUE", (rdr->audisabled == 1) ? "1" : "0"); - } - - // AUprovid - if(rdr->auprovid) - { tpl_printf(vars, TPLADD, "AUPROVID", "%06X", rdr->auprovid); } - - if(rdr->ecmnotfoundlimit) - { tpl_printf(vars, TPLADD, "ECMNOTFOUNDLIMIT", "%u", rdr->ecmnotfoundlimit); } - -#ifdef READER_IRDETO - // Force Irdeto - if(!apicall) - { - tpl_addVar(vars, TPLADD, "FORCEIRDETOCHECKED", (rdr->force_irdeto == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "FORCEIRDETOVALUE", (rdr->force_irdeto == 1) ? "1" : "0"); - } -#endif - -#ifdef READER_CRYPTOWORKS - // needsglobalfirst - if(!apicall) - { - tpl_addVar(vars, TPLADD, "NEEDSGLOBALFIRST", (rdr->needsglobalfirst == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "NEEDSGLOBALFIRST", (rdr->needsglobalfirst == 1) ? "1" : "0"); - } -#endif -#ifdef WITH_CARDREADER - // RSA Key - for(i = 0; i < rdr->rsa_mod_length; i++) - { tpl_printf(vars, TPLAPPEND, "RSAKEY", "%02X", rdr->rsa_mod[i]); } - - // 3DES Key - for(i = 0; i < rdr->des_key_length; i++) - { tpl_printf(vars, TPLAPPEND, "DESKEY", "%02X", rdr->des_key[i]); } - - // BoxKey - for(i = 0; i < rdr->boxkey_length ; i++) - { tpl_printf(vars, TPLAPPEND, "BOXKEY", "%02X", rdr->boxkey[i]); } -#endif -#ifdef READER_CONAX - for(i = 0; i < rdr->cwpk_mod_length; i++) - { tpl_printf(vars, TPLAPPEND, "CWPKKEY", "%02X", rdr->cwpk_mod[i]); } -#endif -#ifdef READER_NAGRA - // nuid (CAK6.3) - for(i = 0; i < rdr->cak63nuid_length; i++) - { tpl_printf(vars, TPLAPPEND, "CAK63NUID", "%02X", rdr->cak63nuid[i]); } - - // cwekey (CAK6.3) - for(i = 0; i < rdr->cak63cwekey_length; i++) - { tpl_printf(vars, TPLAPPEND, "CAK63CWEKEY", "%02X", rdr->cak63cwekey[i]); } -#endif - -#ifdef READER_NAGRA_MERLIN - int32_t j; - - // idird (CAK7) - for(i = 0; i < rdr->idird_length; i++) - { tpl_printf(vars, TPLAPPEND, "IDIRD", "%02X", rdr->idird[i]); } - - // cmd0e_provider (CAK7) - for(i = 0; i < rdr->cmd0eprov_length; i++) - { tpl_printf(vars, TPLAPPEND, "CMD0EPROV", "%02X", rdr->cmd0eprov[i]); } - - // mod1 (CAK7) - for(i = 0; i < rdr->mod1_length ; i++) - { tpl_printf(vars, TPLAPPEND, "MOD1", "%02X", rdr->mod1[i]); } - - // mod2 (CAK7) - for(i = 0; i < rdr->mod2_length ; i++) - { tpl_printf(vars, TPLAPPEND, "MOD2", "%02X", rdr->mod2[i]); } - - // key3588 (CAK7) - for(i = 0; i < rdr->key3588_length; i++) - { tpl_printf(vars, TPLAPPEND, "KEY3588", "%02X", rdr->key3588[i]); } - - // key3310 (CAK7) - for(i = 0; i < rdr->key3310_length; i++) - { tpl_printf(vars, TPLAPPEND, "KEY3310", "%02X", rdr->key3310[i]); } - - // key3460 (CAK7) - for(i = 0; i < rdr->key3460_length; i++) - { tpl_printf(vars, TPLAPPEND, "KEY3460", "%02X", rdr->key3460[i]); } - - // data50 (CAK7) - for(i = 0; i < rdr->data50_length; i++) - { tpl_printf(vars, TPLAPPEND, "DATA50", "%02X", rdr->data50[i]); } - - // mod50 (CAK7) - for(i = 0; i < rdr->mod50_length; i++) - { tpl_printf(vars, TPLAPPEND, "MOD50", "%02X", rdr->mod50[i]); } - - // nuid (CAK7) - for(i = 0; i < rdr->nuid_length; i++) - { tpl_printf(vars, TPLAPPEND, "NUID", "%02X", rdr->nuid[i]); } - - // OTP CSC (CAK7) - for(i = 0; i < rdr->otpcsc_length; i++) - { tpl_printf(vars, TPLAPPEND, "OTPCSC", "%02X", rdr->otpcsc[i]); } - - // OTA CSC (CAK7) - for(i = 0; i < rdr->otacsc_length; i++) - { tpl_printf(vars, TPLAPPEND, "OTACSC", "%02X", rdr->otacsc[i]); } - - // Force Pairing Type (CAK7) - for(i = 0; i < rdr->forcepair_length; i++) - { tpl_printf(vars, TPLAPPEND, "FORCEPAIR", "%02X", rdr->forcepair[i]); } - - // cwekeys (CAK7) - for(j = 0; j < 17; j++) - { - char key[9] = "CWEKEY"; - if(j > 9) - { - key[6] = '1'; - key[7] = '0' + (j - 10); - } - else - { - key[6] = '0' + j; - } - for(i = 0; i < rdr->cwekey_length[j]; i++) - { tpl_printf(vars, TPLAPPEND, key, "%02X", rdr->cwekey[j][i]); } - } - - // force_cw_swap - if(rdr->forcecwswap) - { tpl_addVar(vars, TPLADD, "FORCECWSWAPCHECKED", "checked"); } - - // only_even_SA - if(rdr->evensa) - { tpl_addVar(vars, TPLADD, "EVENSACHECKED", "checked"); } - - // force_EMM_82 - if(rdr->forceemmg) - { tpl_addVar(vars, TPLADD, "FORCEEMMGCHECKED", "checked"); } - - // OTA_CWPKs - if(rdr->cwpkota) - { tpl_addVar(vars, TPLADD, "CWPKOTACHECKED", "checked"); } - - tpl_printf(vars, TPLADD, "TMP", "NAGRACAK7HEADERMODE%d", rdr->headermode); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - - // CWPK CaID (CAK7) - for(i = 0; i < rdr->cwpkcaid_length ; i++) - { tpl_printf(vars, TPLAPPEND, "CWPKCAID", "%02X", rdr->cwpkcaid[i]); } - - // cak7_mode - if(rdr->cak7_mode) - { tpl_addVar(vars, TPLADD, "NAGRACAK7MODECHECKED", "checked"); } -#endif - -#ifdef READER_VIDEOGUARD - tpl_printf(vars, TPLADD, "TMP", "CARDSTARTDATEBASEMONTH%d", rdr->card_startdate_basemonth); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - - tpl_printf(vars, TPLADD, "CARDSTARTDATEBASEYEAR", "%d", rdr->card_startdate_baseyear); - - tpl_printf(vars, TPLADD, "TMP", "CARDEXPIREDATEBASEMONTH%d", rdr->card_expiredate_basemonth); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - - tpl_printf(vars, TPLADD, "CARDEXPIREDATEBASEYEAR", "%d", rdr->card_expiredate_baseyear); - - // ins7E - if(rdr->ins7E[0x1A]) - { - for(i = 0; i < 26 ; i++) { tpl_printf(vars, TPLAPPEND, "INS7E", "%02X", rdr->ins7E[i]); } - } - // ins42 - if(rdr->ins42[0x25]) - { - for(i = 0; i < 37 ; i++) { tpl_printf(vars, TPLAPPEND, "INS42", "%02X", rdr->ins42[i]); } - } - - // ins7E11 - if(rdr->ins7E11[0x01]) - { - tpl_printf(vars, TPLAPPEND, "INS7E11", "%02X", rdr->ins7E11[0]); - } - - // ins2e06 - if(rdr->ins2e06[0x04]) - { - for(i = 0; i < 4 ; i++) { tpl_printf(vars, TPLAPPEND, "INS2E06", "%02X", rdr->ins2e06[i]); } - } - - // k1 for generic pairing mode - if(rdr->k1_generic[0x10]) - { - for(i = 0; i < rdr->k1_generic[0x10] ; i++) { tpl_printf(vars, TPLAPPEND, "K1_GENERIC", "%02X", rdr->k1_generic[i]); } - } - - // k1 for unique pairing mode - if(rdr->k1_unique[0x10]) - { - for(i = 0; i < rdr->k1_unique[0x10] ; i++) { tpl_printf(vars, TPLAPPEND, "K1_UNIQUE", "%02X", rdr->k1_unique[i]); } - } -#endif - -#ifdef WITH_CARDREADER - // ATR - if(rdr->atr[0]) - for(i = 0; i < rdr->atrlen / 2; i++) - { tpl_printf(vars, TPLAPPEND, "ATR", "%02X", rdr->atr[i]); } -#endif - - // ECM Whitelist - value = mk_t_ecm_whitelist(&rdr->ecm_whitelist); - tpl_addVar(vars, TPLADD, "ECMWHITELIST", value); - free_mk_t(value); - - // ECM Header Whitelist - value = mk_t_ecm_hdr_whitelist(&rdr->ecm_hdr_whitelist); - tpl_addVar(vars, TPLADD, "ECMHEADERWHITELIST", value); - free_mk_t(value); - -#ifdef WITH_CARDREADER - // Deprecated - if(!apicall) - { - tpl_addVar(vars, TPLADD, "DEPRECATEDCHECKED", (rdr->deprecated == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "DEPRECATEDVALUE", (rdr->deprecated == 1) ? "1" : "0"); - } - - // Smargopatch - if(!apicall) - { - tpl_addVar(vars, TPLADD, "SMARGOPATCHCHECKED", (rdr->smargopatch == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "SMARGOPATCHVALUE", (rdr->smargopatch == 1) ? "1" : "0"); - } - - // Autospeed - if(!apicall) - { - tpl_addVar(vars, TPLADD, "AUTOSPEEDCHECKED", (rdr->autospeed == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "AUTOSPEEDVALUE", (rdr->autospeed == 1) ? "1" : "0"); - } - // sc8in1 dtrrts patch - if(!apicall) - { - tpl_addVar(vars, TPLADD, "SC8IN1DTRRTSPATCHCHECKED", (rdr->sc8in1_dtrrts_patch == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "SC8IN1DTRRTSPATCHVALUE", (rdr->sc8in1_dtrrts_patch == 1) ? "1" : "0"); - } - -#ifdef READER_VIACCESS - if(!apicall) - { - tpl_addVar(vars, TPLADD, "READOLDCLASSES", (rdr->read_old_classes == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "READOLDCLASSES", (rdr->read_old_classes == 1) ? "1" : "0"); - } -#endif - - // Detect - if(rdr->detect & 0x80) - { tpl_printf(vars, TPLADD, "DETECT", "!%s", RDR_CD_TXT[rdr->detect & 0x7f]); } - else - { tpl_addVar(vars, TPLADD, "DETECT", RDR_CD_TXT[rdr->detect & 0x7f]); } -#endif - - // Ratelimit - if(rdr->ratelimitecm) - { - tpl_printf(vars, TPLADD, "RATELIMITECM", "%d", rdr->ratelimitecm); - // ECMUNIQUE - if(!apicall) - { - tpl_addVar(vars, TPLADD, "ECMUNIQUECHECKED", (rdr->ecmunique == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "ECMUNIQUE", (rdr->ecmunique == 1) ? "1" : "0"); - } - tpl_printf(vars, TPLADD, "RATELIMITTIME", "%d", rdr->ratelimittime); - tpl_printf(vars, TPLADD, "SRVIDHOLDTIME", "%d", rdr->srvidholdtime); - } - // Cooldown - if(rdr->cooldown[0] && rdr->cooldown[1]) - { - tpl_printf(vars, TPLADD, "COOLDOWNDELAY", "%d", rdr->cooldown[0]); - tpl_printf(vars, TPLADD, "COOLDOWNTIME", "%d", rdr->cooldown[1]); - } - // Max parallel services - tpl_printf(vars, TPLADD, "MAXPARALLEL", "%d", rdr->maxparallel); - // Parallelfactor: format as float with dot (comma would break URL parameters) - tpl_printf(vars, TPLADD, "PARALLELFACTOR", "%.1f", rdr->parallelfactor >= 0 ? rdr->parallelfactor : 2.0); - tpl_printf(vars, TPLADD, "PARALLELTIMEOUT", "%d", rdr->paralleltimeout); -#ifdef WITH_CARDREADER - // Frequencies - tpl_printf(vars, TPLADD, "MHZ", "%d", rdr->mhz); - tpl_printf(vars, TPLADD, "CARDMHZ", "%d", rdr->cardmhz); -#endif - - // Device - if(!apicall) - { - tpl_addVar(vars, TPLADD, "DEVICE", xml_encode(vars, rdr->device)); - } - else - { - tpl_addVar(vars, TPLADD, "DEVICE", rdr->device); - } - - if(rdr->r_port) - { tpl_printf(vars, TPLAPPEND, "DEVICE", ",%d", rdr->r_port); } - if(rdr->l_port) - { - if(rdr->r_port) - { tpl_printf(vars, TPLAPPEND, "DEVICE", ",%d", rdr->l_port); } - else - { tpl_printf(vars, TPLAPPEND, "DEVICE", ",,%d", rdr->l_port); } - } - - // Group - value = mk_t_group(rdr->grp); - tpl_addVar(vars, TPLADD, "GRP", value); - free_mk_t(value); - -#ifdef WITH_LB - if(rdr->lb_weight) - { tpl_printf(vars, TPLADD, "LBWEIGHT", "%d", rdr->lb_weight); } -#endif - - //services - if(!apicall) - { - struct s_sidtab *sidtab = cfg.sidtab; - //build matrix - i = 0; - while(sidtab != NULL) - { - tpl_addVar(vars, TPLADD, "SIDLABEL", xml_encode(vars, sidtab->label)); - if(rdr->sidtabs.ok & ((SIDTABBITS)1 << i)) { tpl_addVar(vars, TPLADD, "CHECKED", "checked"); } - else { tpl_addVar(vars, TPLADD, "CHECKED", ""); } - tpl_addVar(vars, TPLAPPEND, "SIDS", tpl_getTpl(vars, "READERCONFIGSIDOKBIT")); - if(rdr->sidtabs.no & ((SIDTABBITS)1 << i)) { tpl_addVar(vars, TPLADD, "CHECKED", "checked"); } - else { tpl_addVar(vars, TPLADD, "CHECKED", ""); } - tpl_addVar(vars, TPLAPPEND, "SIDS", tpl_getTpl(vars, "READERCONFIGSIDNOBIT")); - if(rdr->lb_sidtabs.ok & ((SIDTABBITS)1 << i)) { tpl_addVar(vars, TPLADD, "CHECKED", "checked"); } - else { tpl_addVar(vars, TPLADD, "CHECKED", ""); } - tpl_addVar(vars, TPLAPPEND, "SIDS", tpl_getTpl(vars, "READERCONFIGSIDLBOKBIT")); - sidtab = sidtab->next; - i++; - } - if(i){ - tpl_addVar(vars, TPLADD, "READERCONFIGSIDINS", tpl_getTpl(vars, "READERCONFIGSID")); - } - } - else - { - value = mk_t_service(&rdr->sidtabs); - if(cs_strlen(value) > 0) - { tpl_addVar(vars, TPLADD, "SERVICES", value); } - free_mk_t(value); - } - - // CAID - value = mk_t_caidtab(&rdr->ctab); - tpl_addVar(vars, TPLADD, "CAIDS", value); - free_mk_t(value); - -#ifdef READER_VIACCESS - // AESkeys - value = mk_t_aeskeys(rdr); - tpl_addVar(vars, TPLADD, "AESKEYS", value); - free_mk_t(value); -#endif - - //ident - value = mk_t_ftab(&rdr->ftab); - tpl_addVar(vars, TPLADD, "IDENTS", value); - free_mk_t(value); - - //CHID - value = mk_t_ftab(&rdr->fchid); - tpl_addVar(vars, TPLADD, "CHIDS", value); - free_mk_t(value); - - //Local cards - value = mk_t_ftab(&rdr->localcards); - tpl_addVar(vars, TPLADD, "LOCALCARDS", value); - free_mk_t(value); - - //class - value = mk_t_cltab(&rdr->cltab); - tpl_addVar(vars, TPLADD, "CLASS", value); - free_mk_t(value); - - if(rdr->cachemm || rdr->logemm) - { tpl_printf(vars, TPLADD, "EMMCACHE", "%d,%d,%d,%d", rdr->cachemm, rdr->rewritemm, rdr->logemm, rdr->deviceemm); } - - //savenano - value = mk_t_nano(rdr->s_nano); - tpl_addVar(vars, TPLADD, "SAVENANO", value); - free_mk_t(value); - - //blocknano - value = mk_t_nano(rdr->b_nano); - tpl_addVar(vars, TPLADD, "BLOCKNANO", value); - free_mk_t(value); - - // Blocke EMM - if(!apicall) - { - tpl_addVar(vars, TPLADD, "BLOCKEMMUNKNOWNCHK", (rdr->blockemm & EMM_UNKNOWN) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "BLOCKEMMUNIQCHK", (rdr->blockemm & EMM_UNIQUE) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "BLOCKEMMSHAREDCHK", (rdr->blockemm & EMM_SHARED) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "BLOCKEMMGLOBALCHK", (rdr->blockemm & EMM_GLOBAL) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "BLOCKEMMUNKNOWNVALUE", (rdr->blockemm & EMM_UNKNOWN) ? "1" : "0"); - tpl_addVar(vars, TPLADD, "BLOCKEMMUNIQVALUE", (rdr->blockemm & EMM_UNIQUE) ? "1" : "0"); - tpl_addVar(vars, TPLADD, "BLOCKEMMSHAREDVALUE", (rdr->blockemm & EMM_SHARED) ? "1" : "0"); - tpl_addVar(vars, TPLADD, "BLOCKEMMGLOBALVALUE", (rdr->blockemm & EMM_GLOBAL) ? "1" : "0"); - } - - // Save EMM - if(!apicall) - { - tpl_addVar(vars, TPLADD, "SAVEEMMUNKNOWNCHK", (rdr->saveemm & EMM_UNKNOWN) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "SAVEEMMUNIQCHK", (rdr->saveemm & EMM_UNIQUE) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "SAVEEMMSHAREDCHK", (rdr->saveemm & EMM_SHARED) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "SAVEEMMGLOBALCHK", (rdr->saveemm & EMM_GLOBAL) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "SAVEEMMUNKNOWNVALUE", (rdr->saveemm & EMM_UNKNOWN) ? "1" : "0"); - tpl_addVar(vars, TPLADD, "SAVEEMMUNIQVALUE", (rdr->saveemm & EMM_UNIQUE) ? "1" : "0"); - tpl_addVar(vars, TPLADD, "SAVEEMMSHAREDVALUE", (rdr->saveemm & EMM_SHARED) ? "1" : "0"); - tpl_addVar(vars, TPLADD, "SAVEEMMGLOBALVALUE", (rdr->saveemm & EMM_GLOBAL) ? "1" : "0"); - } - - value = mk_t_emmbylen(rdr); - if(cs_strlen(value) > 0) - { tpl_addVar(vars, TPLADD, "BLOCKEMMBYLEN", value); } - free_mk_t(value); - -#ifdef MODULE_CCCAM - if(!strcmp(rdr->cc_version, "2.0.11")) - { - tpl_addVar(vars, TPLADD, "CCCVERSIONSELECTED0", "selected"); - } - else if(!strcmp(rdr->cc_version, "2.1.1")) - { - tpl_addVar(vars, TPLADD, "CCCVERSIONSELECTED1", "selected"); - } - else if(!strcmp(rdr->cc_version, "2.1.2")) - { - tpl_addVar(vars, TPLADD, "CCCVERSIONSELECTED2", "selected"); - } - else if(!strcmp(rdr->cc_version, "2.1.3")) - { - tpl_addVar(vars, TPLADD, "CCCVERSIONSELECTED3", "selected"); - } - else if(!strcmp(rdr->cc_version, "2.1.4")) - { - tpl_addVar(vars, TPLADD, "CCCVERSIONSELECTED4", "selected"); - } - else if(!strcmp(rdr->cc_version, "2.2.0")) - { - tpl_addVar(vars, TPLADD, "CCCVERSIONSELECTED5", "selected"); - } - else if(!strcmp(rdr->cc_version, "2.2.1")) - { - tpl_addVar(vars, TPLADD, "CCCVERSIONSELECTED6", "selected"); - } - else if(!strcmp(rdr->cc_version, "2.3.0")) - { - tpl_addVar(vars, TPLADD, "CCCVERSIONSELECTED7", "selected"); - } - else if(!strcmp(rdr->cc_version, "2.3.1")) - { - tpl_addVar(vars, TPLADD, "CCCVERSIONSELECTED8", "selected"); - } - else if(!strcmp(rdr->cc_version, "2.3.2")) - { - tpl_addVar(vars, TPLADD, "CCCVERSIONSELECTED9", "selected"); - } -#endif - -#ifdef READER_VIDEOGUARD - tpl_printf(vars, TPLADD, "TMP", "NDSVERSION%d", rdr->ndsversion); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - - tpl_printf(vars, TPLADD, "TMP", "NDSREADTIERS%d", rdr->readtiers); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); -#endif -#ifdef READER_NAGRA - tpl_printf(vars, TPLADD, "TMP", "NAGRAREAD%d", rdr->nagra_read); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - - if(rdr->detect_seca_nagra_tunneled_card) - { tpl_addVar(vars, TPLADD, "NAGRADETECTSECACARDCHECKED", "checked"); } -#endif -#ifdef READER_TONGFANG - if(rdr->tongfang3_calibsn) - { tpl_printf(vars, TPLADD, "TONGFANGCALIBSN", "%08X", rdr->tongfang3_calibsn); } - - if(rdr->tongfang_boxid) - { tpl_printf(vars, TPLADD, "TONGFANGBOXID", "%08X", rdr->tongfang_boxid); } - - if(rdr->tongfang3_deskey_length > 0) - { - for(i = 0; i < rdr->tongfang3_deskey_length ; i++) - { - tpl_printf(vars, TPLAPPEND, "TONGFANGDESKEY", "%02X", rdr->tongfang3_deskey[i]); - } - } - - if(rdr->stbid_length > 0) - { - for(i = 0; i < rdr->stbid_length ; i++) - { - tpl_printf(vars, TPLAPPEND, "STBID", "%02X", rdr->stbid[i]); - } - } - -#endif - -#ifdef MODULE_CCCAM - tpl_printf(vars, TPLADD, "CCCMAXHOPS", "%d", rdr->cc_maxhops); - tpl_printf(vars, TPLADD, "CCCMINDOWN", "%d", rdr->cc_mindown); - tpl_printf(vars, TPLADD, "CCCRESHARE", "%d", rdr->cc_reshare); - tpl_printf(vars, TPLADD, "RESHARE", "%d", cfg.cc_reshare); - tpl_printf(vars, TPLADD, "CCCRECONNECT", "%d", rdr->cc_reconnect); - - if(rdr->cc_want_emu) - { tpl_addVar(vars, TPLADD, "CCCWANTEMUCHECKED", "checked"); } - if(rdr->cc_keepalive) - { tpl_addVar(vars, TPLADD, "KEEPALIVECHECKED", "checked"); } -#endif - -#ifdef MODULE_GBOX - tpl_printf(vars, TPLADD, "GBOXMAXDISTANCE", "%d", rdr->gbox_maxdist); - tpl_printf(vars, TPLADD, "GBOXMAXECMSEND", "%d", rdr->gbox_maxecmsend); - tpl_printf(vars, TPLADD, "GBOXRESHARE", "%d", rdr->gbox_reshare); - tpl_printf(vars, TPLADD, "PEERGBOXID", "%04X", gbox_convert_password_to_id((uint32_t)a2i(rdr->r_pwd, 4))); - tpl_addVar(vars, TPLADD, "PEERONLSTAT", (get_peer_onl_status(gbox_convert_password_to_id((uint32_t)a2i(rdr->r_pwd, 4)))) ? "checked" : ""); - tpl_printf(vars, TPLADD, "FORCEREMM", "%d", rdr->gbox_force_remm); - tpl_printf(vars, TPLADD, "CMDHERE", rdr->send_offline_cmd ? "checked" : ""); - - if(rdr->blockemm & 0x80) - { - tpl_addVar(vars, TPLADD, "REMMCNLDCHK", "checked"); - tpl_printf(vars, TPLADD, "GBOXREMMPEER", "%04X", rdr->gbox_remm_peer); - tpl_addVar(vars, TPLADD, "REMMUNIQCHK", (rdr->blockemm & EMM_UNIQUE) ? "" : "checked"); - tpl_addVar(vars, TPLADD, "REMMSHAREDCHK", (rdr->blockemm & EMM_SHARED) ? "" : "checked"); - tpl_addVar(vars, TPLADD, "REMMGLOBALCHK", (rdr->blockemm & EMM_GLOBAL) ? "" : "checked"); - tpl_addVar(vars, TPLADD, "REMMEMMUNKNOWNCHK", (rdr->blockemm & EMM_UNKNOWN) ? "" : "checked"); - } - if(rdr->gbox_gsms_peer) - { - tpl_printf(vars, TPLADD, "LASTGSMS", "%s", rdr->last_gsms); - tpl_printf(vars, TPLADD, "GBOXGSMSPEER", "%04X", rdr->gbox_gsms_peer); - } -#endif - -#ifdef READER_DRECAS - tpl_addVar(vars, TPLADD, "STMKEYS", rdr->stmkeys); -#endif - -#if defined(READER_DRE) || defined(READER_DRECAS) - tpl_addVar(vars, TPLADD, "USERSCRIPT", rdr->userscript); -#endif - -#ifdef WITH_EMU - //emu_auproviders - value = mk_t_ftab(&rdr->emu_auproviders); - tpl_addVar(vars, TPLADD, "EMUAUPROVIDERS", value); - free_mk_t(value); - - // Date-coded BISS keys - if(!apicall) - { - tpl_addVar(vars, TPLADD, "EMUDATECODEDENABLED", (rdr->emu_datecodedenabled == 1) ? "checked" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "EMUDATECODEDENABLED", (rdr->emu_datecodedenabled == 1) ? "1" : "0"); - } -#endif - - tpl_addVar(vars, TPLADD, "PROTOCOL", reader_get_type_desc(rdr, 0)); - - // Show only parameters which needed for the reader - switch(rdr->typ) - { - case R_CONSTCW: - case R_DB2COM1: - case R_DB2COM2: - case R_MOUSE : - case R_DRECAS : - case R_MP35: - case R_SC8in1 : - case R_SMART : - case R_INTERNAL: - case R_SERIAL : - case R_PCSC : - tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGSTDHWREADERBIT")); - break; - case R_CAMD35 : - tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGCAMD35BIT")); - break; - case R_EMU : - tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGEMUBIT")); - break; - case R_CS378X : - tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGCS378XBIT")); - break; - case R_RADEGAST: - tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGRADEGASTBIT")); - break; - case R_SCAM: - tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGSCAMBIT")); - break; - case R_GHTTP: - tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGGHTTPBIT")); - break; - case R_GBOX: - tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGGBOXBIT")); -#if defined (MODULE_CCCAM) && defined (MODULE_GBOX) - if(cfg.cc_gbx_reshare_en) - { - tpl_printf(vars, TPLADD, "GBOXCCCAMRESHARE", "%d", rdr->gbox_cccam_reshare); - value = mk_t_ftab(&rdr->ccc_gbx_reshare_ident); - tpl_addVar(vars, TPLADD, "CCCGBXRESHAREIDENT", value); - free_mk_t(value); - tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "GBOXCCCAMRESHAREBIT")); - } -#endif - tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERINFOGBOXREMM")); - break; - case R_NEWCAMD: - if(rdr->ncd_proto == NCD_525) - { - tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGNCD525BIT")); - } - else if(rdr->ncd_proto == NCD_524) - { - tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGNCD524BIT")); - } - break; -#ifdef MODULE_CCCAM - case R_CCCAM : - tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGCCCAMBIT")); - break; -#endif - default : - tpl_addMsg(vars, "Error: protocol not resolvable"); - break; - - } - -#ifdef MODULE_CCCAM - if(rdr->typ != R_CCCAM && rdr->typ != R_GBOX) - { - tpl_printf(vars, TPLADD, "CCCHOP", "%d", rdr->cc_hop); - tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGHOPBIT")); - } -#endif - -#ifdef CS_CACHEEX_AIO - return tpl_getTpl(vars, "READERCONFIGAIO"); -#else - return tpl_getTpl(vars, "READERCONFIG"); -#endif -} - -static char *send_oscam_reader_stats(struct templatevars *vars, struct uriparams *params, int32_t apicall) -{ - - if(!apicall) { setActiveMenu(vars, MNU_READERS); } - - int8_t error; - struct s_client *cl = NULL; - struct s_reader *rdr; - - rdr = get_reader_by_label(getParam(params, "label")); - error = (rdr ? 0 : 1); - - if(!error && rdr) - { - cl = rdr->client; - error = (cl ? 0 : 1); - } - - if(error) - { - tpl_addVar(vars, TPLAPPEND, "READERSTATSROW", tpl_getTpl(vars, "READERSTATSROWBIT")); - if(!apicall) - { return tpl_getTpl(vars, "READERSTATS"); } - else - { return tpl_getTpl(vars, "APIREADERSTATS"); } - } - -#ifdef WITH_LB - char *stxt[] = {"found", "cache1", "cache2", "cache3", - "not found", "timeout", "sleeping", - "fake", "invalid", "corrupt", "no card", "expdate", - "disabled", "stopped" - }; - - if(strcmp(getParam(params, "action"), "resetstat") == 0) - { - char *rcs = getParam(params, "rc"); - int32_t retval = 0; - if(cs_strlen(rcs) > 0) - { - int8_t rc; - rc = atoi(rcs); - retval = clean_stat_by_rc(rdr, rc, 0); - cs_log("Reader %s stats %d %s entr%s deleted by WebIF from %s", - rdr->label, retval, stxt[rc], - retval == 1 ? "y" : "ies", - cs_inet_ntoa(GET_IP())); - } - else - { - clear_reader_stat(rdr); - cs_log("Reader %s stats resetted by WebIF from %s", rdr->label, cs_inet_ntoa(GET_IP())); - } - - } - - if(strcmp(getParam(params, "action"), "deleterecord") == 0) - { - char *record = getParam(params, "record"); - if(cs_strlen(record) > 0) - { - int32_t retval = 0; - uint32_t caid, provid, sid, cid, len; - sscanf(record, "%4x@%6x:%4x:%4x:%4x", &caid, &provid, &sid, &cid, &len); - retval = clean_stat_by_id(rdr, caid, provid, sid, cid, len); - cs_log("Reader %s stats %d entr%s deleted by WebIF from %s", - rdr->label, retval, - retval == 1 ? "y" : "ies", - cs_inet_ntoa(GET_IP())); - } - } - - if(strcmp(getParam(params, "action"), "updateecmlen") == 0) - { - update_ecmlen_from_stat(rdr); - write_server(); - } - -#endif - - tpl_addVar(vars, TPLADD, "READERNAME", xml_encode(vars, rdr->label)); - tpl_addVar(vars, TPLADD, "LABEL", xml_encode(vars, rdr->label)); - tpl_addVar(vars, TPLADD, "ENCODEDLABEL", urlencode(vars, rdr->label)); - - if(apicall) - { - int32_t i, emmcount = 0; - char *ttxt[] = {"unknown", "unique", "shared", "global"}; - - for(i = 0; i < 4; i++) - { - tpl_addVar(vars, TPLADD, "EMMRESULT", "error"); - tpl_addVar(vars, TPLADD, "EMMTYPE", ttxt[i]); - tpl_printf(vars, TPLADD, "EMMCOUNT", "%d", rdr->emmerror[i]); - tpl_addVar(vars, TPLAPPEND, "EMMSTATS", tpl_getTpl(vars, "APIREADERSTATSEMMBIT")); - emmcount += rdr->emmerror[i]; - tpl_printf(vars, TPLADD, "TOTALERROR", "%d", emmcount); - } - emmcount = 0; - for(i = 0; i < 4; i++) - { - tpl_addVar(vars, TPLADD, "EMMRESULT", "written"); - tpl_addVar(vars, TPLADD, "EMMTYPE", ttxt[i]); - tpl_printf(vars, TPLADD, "EMMCOUNT", "%d", rdr->emmwritten[i]); - tpl_addVar(vars, TPLAPPEND, "EMMSTATS", tpl_getTpl(vars, "APIREADERSTATSEMMBIT")); - emmcount += rdr->emmwritten[i]; - tpl_printf(vars, TPLADD, "TOTALWRITTEN", "%d", emmcount); - } - emmcount = 0; - for(i = 0; i < 4; i++) - { - tpl_addVar(vars, TPLADD, "EMMRESULT", "skipped"); - tpl_addVar(vars, TPLADD, "EMMTYPE", ttxt[i]); - tpl_printf(vars, TPLADD, "EMMCOUNT", "%d", rdr->emmskipped[i]); - tpl_addVar(vars, TPLAPPEND, "EMMSTATS", tpl_getTpl(vars, "APIREADERSTATSEMMBIT")); - emmcount += rdr->emmskipped[i]; - tpl_printf(vars, TPLADD, "TOTALSKIPPED", "%d", emmcount); - } - emmcount = 0; - for(i = 0; i < 4; i++) - { - tpl_addVar(vars, TPLADD, "EMMRESULT", "blocked"); - tpl_addVar(vars, TPLADD, "EMMTYPE", ttxt[i]); - tpl_printf(vars, TPLADD, "EMMCOUNT", "%d", rdr->emmblocked[i]); - tpl_addVar(vars, TPLAPPEND, "EMMSTATS", tpl_getTpl(vars, "APIREADERSTATSEMMBIT")); - emmcount += rdr->emmblocked[i]; - tpl_printf(vars, TPLADD, "TOTALBLOCKED", "%d", emmcount); - } - } - - if(apicall) - { - char *txt = "UNDEF"; - switch(rdr->card_status) - { - case NO_CARD: - if(rdr->typ == R_GBOX) - { txt = "ONL no crd"; } - else - { txt = "OFF"; } - break; - case UNKNOWN: - txt = "UNKNOWN"; - break; - case READER_DEVICE_ERROR: - txt = "READER DEVICE ERROR"; - break; - case CARD_NEED_INIT: - if(rdr->typ == R_GBOX) - { txt = "OFFLINE"; } - else - { txt = "NEEDINIT"; } - break; - case CARD_INSERTED: - if(cl->typ == 'p') - { - if(rdr->typ == R_GBOX) - { txt = "ONL w/crd"; } - else - { txt = "CONNECTED"; } - } - else - { txt = "CARDOK"; } - break; - case CARD_FAILURE: - txt = "ERROR"; - break; - default: - txt = "UNDEF"; - } - tpl_addVar(vars, TPLADD, "READERSTATUS", txt); - tpl_printf(vars, TPLADD, "READERCAID", "%04X", rdr->caid); - } - - int32_t rowcount = 0; - uint64_t ecmcount = 0; - time_t lastaccess = 0; - -#ifdef WITH_LB - int32_t rc2hide = (-1); - if(cs_strlen(getParam(params, "hide")) > 0) - { rc2hide = atoi(getParam(params, "hide")); } - - int32_t rc2show = (-1); - if(cs_strlen(getParam(params, "show")) > 0) - { rc2show = atoi(getParam(params, "show")); } - - if(rdr->lb_stat) - { - int32_t statsize; - // @todo alno: sort by click, 0=ascending, 1=descending (maybe two buttons or reverse on second click) - READER_STAT **statarray = get_sorted_stat_copy(rdr, 0, &statsize); - char channame[CS_SERVICENAME_SIZE]; - for(; rowcount < statsize; ++rowcount) - { - READER_STAT *s = statarray[rowcount]; - if(!(s->rc == rc2hide) && ((rc2show == -1) || (s->rc == rc2show))) - { - struct tm lt; - localtime_r(&s->last_received.time, <); // fixme we need walltime! - ecmcount += s->ecm_count; - if(!apicall) - { - tpl_printf(vars, TPLADD, "CHANNEL", "%04X@%06X:%04X:%04X", s->caid, s->prid, s->srvid, s->chid); - tpl_addVar(vars, TPLADD, "CHANNELNAME", xml_encode(vars, get_servicename(cur_client(), s->srvid, s->prid, s->caid, channame, sizeof(channame)))); - tpl_printf(vars, TPLADD, "ECMLEN", "%04hX", s->ecmlen); - tpl_addVar(vars, TPLADD, "RC", stxt[s->rc]); - tpl_printf(vars, TPLADD, "TIME", PRINTF_LOCAL_D " ms", s->time_avg); - if(s->time_stat[s->time_idx]) - { tpl_printf(vars, TPLADD, "TIMELAST", PRINTF_LOCAL_D " ms", s->time_stat[s->time_idx]); } - else - { tpl_addVar(vars, TPLADD, "TIMELAST", ""); } - tpl_printf(vars, TPLADD, "COUNT", PRINTF_LOCAL_D, s->ecm_count); - - if(s->last_received.time) - { - tpl_printf(vars, TPLADD, "LAST", "%02d.%02d.%02d %02d:%02d:%02d", lt.tm_mday, lt.tm_mon + 1, lt.tm_year % 100, lt.tm_hour, lt.tm_min, lt.tm_sec); - - } - else - { - tpl_addVar(vars, TPLADD, "LAST", "never"); - } - } - else - { - tpl_printf(vars, TPLADD, "ECMCAID", "%04X", s->caid); - tpl_printf(vars, TPLADD, "ECMPROVID", "%06X", s->prid); - tpl_printf(vars, TPLADD, "ECMSRVID", "%04X", s->srvid); - tpl_printf(vars, TPLADD, "ECMLEN", "%04hX", s->ecmlen); - tpl_addVar(vars, TPLADD, "ECMCHANNELNAME", xml_encode(vars, get_servicename(cur_client(), s->srvid, s->prid, s->caid, channame, sizeof(channame)))); - tpl_printf(vars, TPLADD, "ECMTIME", PRINTF_LOCAL_D, s->time_avg); - tpl_printf(vars, TPLADD, "ECMTIMELAST", PRINTF_LOCAL_D, s->time_stat[s->time_idx]); - tpl_printf(vars, TPLADD, "ECMRC", "%d", s->rc); - tpl_addVar(vars, TPLADD, "ECMRCS", stxt[s->rc]); - if(s->last_received.time) - { - char tbuffer [30]; - strftime(tbuffer, 30, "%Y-%m-%dT%H:%M:%S%z", <); - tpl_addVar(vars, TPLADD, "ECMLAST", tbuffer); - } - else - { - tpl_addVar(vars, TPLADD, "ECMLAST", ""); - } - tpl_printf(vars, TPLADD, "ECMCOUNT", PRINTF_LOCAL_D, s->ecm_count); - - if(s->last_received.time > lastaccess) - { lastaccess = s->last_received.time; } - } - - if(!apicall) - { - if(s->rc == E_NOTFOUND) - { - tpl_addVar(vars, TPLAPPEND, "READERSTATSROWNOTFOUND", tpl_getTpl(vars, "READERSTATSBIT")); - tpl_addVar(vars, TPLADD, "RESETA", urlencode(vars, rdr->label)); - tpl_addVar(vars, TPLADD, "READERSTATSNFHEADLINE", tpl_getTpl(vars, "READERSTATSROWNOTFOUNDBIT")); - } - else if(s->rc == E_TIMEOUT) - { - tpl_addVar(vars, TPLAPPEND, "READERSTATSROWTIMEOUT", tpl_getTpl(vars, "READERSTATSBIT")); - tpl_addVar(vars, TPLADD, "RESETB", urlencode(vars, rdr->label)); - tpl_addVar(vars, TPLADD, "READERSTATSTOHEADLINE", tpl_getTpl(vars, "READERSTATSROWTIMEOUTBIT")); - } - else if(s->rc == E_INVALID) - { - tpl_addVar(vars, TPLAPPEND, "READERSTATSROWINVALID", tpl_getTpl(vars, "READERSTATSBIT")); - tpl_addVar(vars, TPLADD, "RESETC", urlencode(vars, rdr->label)); - tpl_addVar(vars, TPLADD, "READERSTATSIVHEADLINE", tpl_getTpl(vars, "READERSTATSROWINVALIDBIT")); - } - else - { tpl_addVar(vars, TPLAPPEND, "READERSTATSROWFOUND", tpl_getTpl(vars, "READERSTATSBIT")); } - } - else - { - - tpl_addVar(vars, TPLAPPEND, "ECMSTATS", tpl_getTpl(vars, "APIREADERSTATSECMBIT")); - } - } - } - NULLFREE(statarray); - } - else -#endif - tpl_addVar(vars, TPLAPPEND, "READERSTATSROW", tpl_getTpl(vars, "READERSTATSNOSTATS")); - - tpl_printf(vars, TPLADD, "ROWCOUNT", "%d", rowcount); - - if(lastaccess > 0) - { - char tbuffer [30]; - struct tm lt; - localtime_r(&lastaccess, <); - strftime(tbuffer, 30, "%Y-%m-%dT%H:%M:%S%z", <); - tpl_addVar(vars, TPLADD, "LASTACCESS", tbuffer); - } - else - { - tpl_addVar(vars, TPLADD, "LASTACCESS", ""); - } - - if(apicall) - { - if(cl) - { - char *value = get_ecm_historystring(cl); - tpl_addVar(vars, TPLADD, "ECMHISTORY", value); - free_mk_t(value); - } - } - - tpl_printf(vars, TPLADD, "TOTALECM", "%'" PRIu64, ecmcount); - - if(!apicall) - { return tpl_getTpl(vars, "READERSTATS"); } - else - { return tpl_getTpl(vars, "APIREADERSTATS"); } -} - -static char *send_oscam_user_config_edit(struct templatevars *vars, struct uriparams *params, int32_t apicall) -{ - struct s_auth *account, *ptr, *chk; - char user[sizeof(first_client->account->usr)]; - - int32_t i; - int existing_insert = 0; - - if(!apicall) { setActiveMenu(vars, MNU_USERS); } - - if(strcmp(getParam(params, "action"), "Save As") == 0) { cs_strncpy(user, getParam(params, "newuser"), sizeof(user)); } - else { cs_strncpy(user, getParam(params, "user"), sizeof(user)); } - - account = NULL; - for(chk = cfg.account; chk != NULL; chk = chk->next) - { - if(strcmp(user, chk->usr) == 0) - { account = chk; } - if(!existing_insert) - { - tpl_printf(vars, TPLADD, "EXISTING_INS", "'%s'", urlencode(vars, chk->usr)); - existing_insert++; - } - else - { - tpl_printf(vars, TPLAPPEND, "EXISTING_INS", ",'%s'", urlencode(vars, chk->usr)); - } - } - - // Create a new user if it doesn't yet - if(account == NULL) - { - i = 1; - while(cs_strlen(user) < 1) - { - snprintf(user, sizeof(user) / sizeof(char) - 1, "NEWUSER%d", i); - for(account = cfg.account; account != NULL && strcmp(user, account->usr) != 0; account = account->next) { ; } - if(account != NULL) { user[0] = '\0'; } - ++i; - } - if(!cs_malloc(&account, sizeof(struct s_auth))) { return "0"; } - if(cfg.account == NULL) { cfg.account = account; } - else - { - for(ptr = cfg.account; ptr != NULL && ptr->next != NULL; ptr = ptr->next) { ; } - ptr->next = account; - } - account_set_defaults(account); - account->disabled = 1; - cs_strncpy((char *)account->usr, user, sizeof(account->usr)); - if(!account->grp) - { account->grp = 1; } - if(write_userdb() != 0) { tpl_addMsg(vars, "Write Config failed!"); } - else if(strcmp(getParam(params, "action"), "Save As") == 0) { tpl_addMsg(vars, "New user has been added with cloned settings"); } - else { tpl_addMsg(vars, "New user has been added with default settings"); } - // no need to refresh anything here as the account is disabled by default and there's no client with this new account anyway! - } - - if((strcmp(getParam(params, "action"), "Save") == 0) || (strcmp(getParam(params, "action"), "Save As") == 0)) - { - char servicelabels[1024] = ""; - - for(i = 0; i < (*params).paramcount; i++) - { - if((strcmp((*params).params[i], "action")) && - (strcmp((*params).params[i], "user")) && - (strcmp((*params).params[i], "newuser")) && - (strcmp((*params).params[i], "part"))) - { - - if(!strcmp((*params).params[i], "services")) - { snprintf(servicelabels + cs_strlen(servicelabels), sizeof(servicelabels) - cs_strlen(servicelabels), "%s,", (*params).values[i]); } - else - { chk_account((*params).params[i], (*params).values[i], account); } - } - } - chk_account("services", servicelabels, account); - - refresh_oscam(REFR_CLIENTS); - - if(write_userdb() != 0) { tpl_addMsg(vars, "Write Config failed!"); } - else if(strcmp(getParam(params, "action"), "Save As") != 0) { tpl_addMsg(vars, "User Account updated and saved"); } - } - - tpl_addVar(vars, TPLADD, "USERNAME", xml_encode(vars, account->usr)); - tpl_addVar(vars, TPLADD, "PASSWORD", xml_encode(vars, account->pwd)); - tpl_addVar(vars, TPLADD, "DESCRIPTION", xml_encode(vars, account->description)); - - //Disabled - if(!apicall) - { - if(account->disabled) - { tpl_addVar(vars, TPLADD, "DISABLEDCHECKED", "checked"); } - } - else - { - tpl_printf(vars, TPLADD, "DISABLEDVALUE", "%d", account->disabled); - } - - //Expirationdate - struct tm timeinfo; - cs_gmtime_r(&account->expirationdate, &timeinfo); - char buf [80]; - strftime(buf, 80, "%Y-%m-%d", &timeinfo); - if(strcmp(buf, "1970-01-01")) { tpl_addVar(vars, TPLADD, "EXPDATE", buf); } - - //Allowed TimeFrame - char *allowedtf = mk_t_allowedtimeframe(account); - tpl_printf(vars, TPLADD, "ALLOWEDTIMEFRAME", "%s", allowedtf); - free_mk_t(allowedtf); - - //Group - char *value = mk_t_group(account->grp); - tpl_addVar(vars, TPLADD, "GROUPS", value); - free_mk_t(value); - - // allowed protocols - value = mk_t_allowedprotocols(account); - tpl_addVar(vars, TPLADD, "ALLOWEDPROTOCOLS", value); - free_mk_t(value); - - //Hostname - tpl_addVar(vars, TPLADD, "DYNDNS", xml_encode(vars, account->dyndns)); - - //Uniq - if(!apicall) - { - tpl_printf(vars, TPLADD, "TMP", "UNIQSELECTED%d", account->uniq); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - } - else - { - tpl_printf(vars, TPLADD, "UNIQVALUE", "%d", account->uniq); - } - - //Sleep - if(!account->tosleep) { tpl_addVar(vars, TPLADD, "SLEEP", "0"); } - else { tpl_printf(vars, TPLADD, "SLEEP", "%d", account->tosleep); } - - //Monlevel selector - if(!apicall) - { - tpl_printf(vars, TPLADD, "TMP", "MONSELECTED%d", account->monlvl); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - } - else - { - tpl_printf(vars, TPLADD, "MONVALUE", "%d", account->monlvl); - } - - //Au - if(account->autoau == 1) - { tpl_addVar(vars, TPLADD, "AUREADER", "1"); } - else if(account->aureader_list) - { - value = mk_t_aureader(account); - tpl_addVar(vars, TPLADD, "AUREADER", value); - free_mk_t(value); - } - - if(!apicall) - { - /* SERVICES */ - struct s_sidtab *sidtab = cfg.sidtab; - //build matrix - i = 0; - while(sidtab != NULL) - { - tpl_addVar(vars, TPLADD, "SIDLABEL", xml_encode(vars, sidtab->label)); - if(account->sidtabs.ok & ((SIDTABBITS)1 << i)) { tpl_addVar(vars, TPLADD, "CHECKED", "checked"); } - else { tpl_addVar(vars, TPLADD, "CHECKED", ""); } - tpl_addVar(vars, TPLAPPEND, "SIDS", tpl_getTpl(vars, "USEREDITSIDOKBIT")); - if(account->sidtabs.no & ((SIDTABBITS)1 << i)) { tpl_addVar(vars, TPLADD, "CHECKED", "checked"); } - else { tpl_addVar(vars, TPLADD, "CHECKED", ""); } - tpl_addVar(vars, TPLAPPEND, "SIDS", tpl_getTpl(vars, "USEREDITSIDNOBIT")); - sidtab = sidtab->next; - i++; - } - if(i){ - tpl_addVar(vars, TPLADD, "USEREDITSIDINS", tpl_getTpl(vars, "USEREDITSID")); - } - } - else - { - value = mk_t_service(&account->sidtabs); - if(cs_strlen(value) > 0) - { tpl_addVar(vars, TPLADD, "SERVICES", value); } - free_mk_t(value); - } - - // CAID - value = mk_t_caidtab(&account->ctab); - tpl_addVar(vars, TPLADD, "CAIDS", value); - free_mk_t(value); - - //ident - value = mk_t_ftab(&account->ftab); - tpl_addVar(vars, TPLADD, "IDENTS", value); - free_mk_t(value); - - //CHID - value = mk_t_ftab(&account->fchid); - tpl_addVar(vars, TPLADD, "CHIDS", value); - free_mk_t(value); - - //class - value = mk_t_cltab(&account->cltab); - tpl_addVar(vars, TPLADD, "CLASS", value); - free_mk_t(value); - - //Betatunnel - value = mk_t_tuntab(&account->ttab); - tpl_addVar(vars, TPLADD, "BETATUNNELS", value); - free_mk_t(value); - - //SUPPRESSCMD08 - if(!apicall) - { - if(account->c35_suppresscmd08) - { tpl_addVar(vars, TPLADD, "SUPPRESSCMD08", "selected"); } - } - else - { - tpl_printf(vars, TPLADD, "SUPPRESSCMD08VALUE", "%d", account->c35_suppresscmd08); - } - - //Sleepsend - if(account->c35_sleepsend) - { - tpl_printf(vars, TPLADD, "SLEEPSEND", "selected"); - } - - //max_connections - tpl_printf(vars, TPLADD, "MAXCONNECTIONS", "%d", account->max_connections); - - //User Max Idle - tpl_printf(vars, TPLADD, "UMAXIDLE", "%d", account->umaxidle); - - //EMM Reassembly selector - if(!apicall) - { - tpl_printf(vars, TPLADD, "TMP", "EMMRSELECTED%d", account->emm_reassembly); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - } - else - { - tpl_printf(vars, TPLADD, "EMMRVALUE", "%d", account->emm_reassembly); - } - - //Prefer local cards - if(!apicall) - { - tpl_printf(vars, TPLADD, "TMP", "PREFERLOCALCARDS%d", account->preferlocalcards); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - char *tmp = NULL; - switch(cfg.preferlocalcards) - { - case -1: - tmp = "-1 - Use Global prefer local cards"; - break; - case 0: - tmp = "0 - local cards like proxied"; - break; - case 1: - tmp = "1 - prefer cache-ex then local cards"; - break; - case 2: - tmp = "2 - prefer local cards above cache-ex"; - break; - } - tpl_addVar(vars, TPLADD, "CFGPREFERLOCALCARDS", tmp); - } - else - { - tpl_printf(vars, TPLADD, "PREFERLOCALCARDSVALUE", "%d", account->preferlocalcards); - } - -#ifdef CS_CACHEEX - // Cacheex - if(!apicall) - { - tpl_printf(vars, TPLADD, "TMP", "CACHEEXSELECTED%d", account->cacheex.mode); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - - } - else - { - tpl_printf(vars, TPLADD, "CACHEEX", "%d", account->cacheex.mode); - } - tpl_printf(vars, TPLADD, "CACHEEX_MAXHOP", "%d", account->cacheex.maxhop); -#ifdef CS_CACHEEX_AIO - tpl_printf(vars, TPLADD, "CACHEEX_MAXHOP_LG", "%d", account->cacheex.maxhop_lg); -#endif - - value = mk_t_cacheex_hitvaluetab(&account->cacheex.filter_caidtab); - //if (cs_strlen(value) > 0) - tpl_printf(vars, TPLADD, "CACHEEX_ECM_FILTER", "%s", value); - free_mk_t(value); - - tpl_addVar(vars, TPLADD, "DCCHECKED", (account->cacheex.drop_csp == 1) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "ARCHECKED", (account->cacheex.allow_request == 1) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "AFCHECKED", (account->cacheex.allow_filter == 1) ? "checked" : ""); -#ifdef CS_CACHEEX_AIO - tpl_addVar(vars, TPLADD, "AMCHECKED", (account->cacheex.allow_maxhop == 1) ? "checked" : ""); -#endif - tpl_addVar(vars, TPLADD, "BLOCKFAKECWSCHECKED", (account->cacheex.block_fakecws == 1) ? "checked" : ""); -#ifdef CS_CACHEEX_AIO - tpl_addVar(vars, TPLADD, "USECWCHECKFORPUSHCHECKED", (account->cacheex.cw_check_for_push == 1) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "LGONLYREMOTESETTINGSCHECKED", (account->cacheex.lg_only_remote_settings == 1) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "LOCALGENERATEDONLYCHECKED", (account->cacheex.localgenerated_only == 1) ? "checked" : ""); - - value = mk_t_ftab(&account->cacheex.lg_only_tab); - tpl_addVar(vars, TPLADD, "LGONLYTAB", value); - free_mk_t(value); - - tpl_addVar(vars, TPLADD, "LOCALGENERATEDONLYINCHECKED", (account->cacheex.localgenerated_only_in == 1) ? "checked" : ""); - - tpl_addVar(vars, TPLADD, "LGONLYINAIOONLYCHECKED", (account->cacheex.lg_only_in_aio_only == 1) ? "checked" : ""); - - value = mk_t_ftab(&account->cacheex.lg_only_in_tab); - tpl_addVar(vars, TPLADD, "LGONLYINTAB", value); - free_mk_t(value); - - value = mk_t_caidvaluetab(&account->cacheex.cacheex_nopushafter_tab); - tpl_addVar(vars, TPLADD, "CACHEEXNOPUSHAFTER", value); - free_mk_t(value); -#endif - tpl_addVar(vars, TPLADD, "NWTCHECKED", (account->no_wait_time == 1) ? "checked" : ""); - tpl_addVar(vars, TPLADD, "DISABLECRCCEX4USER", (account->disablecrccacheex == 1) ? "checked" : ""); - value = mk_t_ftab(&account->disablecrccacheex_only_for); - tpl_addVar(vars, TPLADD, "IGNCRCCEX4USERONLYFOR", value); - free_mk_t(value); - -#endif - -#ifdef CW_CYCLE_CHECK - tpl_addVar(vars, TPLADD, "USERCWCYCLEDISABLE", (account->cwc_disable == 1) ? "checked" : ""); -#endif - - //Keepalive - if(!apicall) - { - if(account->ncd_keepalive) - { tpl_addVar(vars, TPLADD, "KEEPALIVE", "checked"); } - } - else - { - tpl_printf(vars, TPLADD, "KEEPALIVEVALUE", "%d", account->ncd_keepalive); - } - -#ifdef CS_ANTICASC - tpl_printf(vars, TPLADD, "AC_USERS", "%d", account->ac_users); - tpl_printf(vars, TPLADD, "CFGNUMUSERS", "%d", cfg.ac_users); - if(!apicall) - { - tpl_printf(vars, TPLADD, "TMP", "PENALTY%d", account->ac_penalty); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - char *tmp = NULL; - switch(cfg.ac_penalty) - { - case 0: - tmp = "(0) Only write to log"; - break; - case 1: - tmp = "(1) NULL CW"; - break; - case 2: - tmp = "(2) Ban"; - break; - case 3: - tmp = "(3) Real CW delayed"; - break; - } - tpl_addVar(vars, TPLADD, "CFGPENALTY", tmp); - } - else - { - tpl_printf(vars, TPLADD, "PENALTYVALUE", "%d", account->ac_penalty); - } - tpl_printf(vars, TPLADD, "ACOSC_MAX_ECMS_PER_MINUTE", "%d", account->acosc_max_ecms_per_minute); - tpl_printf(vars, TPLADD, "ACOSC_MAX_ACTIVE_SIDS", "%d", account->acosc_max_active_sids); - tpl_printf(vars, TPLADD, "CFG_ACOSC_MAX_ECMS_PER_MINUTE", "%d", cfg.acosc_max_ecms_per_minute); - tpl_printf(vars, TPLADD, "CFG_ACOSC_MAX_ACTIVE_SIDS", "%d", cfg.acosc_max_active_sids); - tpl_printf(vars, TPLADD, "ACOSC_ZAP_LIMIT", "%d", account->acosc_zap_limit); - tpl_printf(vars, TPLADD, "CFG_ACOSC_ZAP_LIMIT", "%d", cfg.acosc_zap_limit); - if(!apicall) - { - tpl_printf(vars, TPLADD, "TMP", "ACOSC_PENALTY%d", account->acosc_penalty); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - char *tmp = NULL; - switch(cfg.acosc_penalty) - { - case -1: - tmp = "(-1) Use Global Value"; - break; - case 0: - tmp = "(0) Only write to log"; - break; - case 1: - tmp = "(1) NULL CW"; - break; - case 2: - tmp = "(2) Ban"; - break; - case 3: - tmp = "(3) CW delayed"; - break; - case 4: - tmp = "(4) Hidecards"; - break; - } - tpl_addVar(vars, TPLADD, "CFG_ACOSC_PENALTY", tmp); - } else - { - tpl_printf(vars, TPLADD, "ACOSC_PENALTYVALUE", "%d", account->acosc_penalty); - } - - tpl_printf(vars, TPLADD, "ACOSC_PENALTY_DURATION", "%d", account->acosc_penalty_duration); - tpl_printf(vars, TPLADD, "CFG_ACOSC_PENALTY_DURATION", "%d", cfg.acosc_penalty_duration); - tpl_printf(vars, TPLADD, "ACOSC_DELAY", "%d", account->acosc_delay); - tpl_printf(vars, TPLADD, "CFG_ACOSC_DELAY", "%d", cfg.acosc_delay); -#endif - -#ifdef MODULE_CCCAM - tpl_printf(vars, TPLADD, "CCCMAXHOPS", "%d", account->cccmaxhops); - tpl_printf(vars, TPLADD, "CCCRESHARE", "%d", account->cccreshare); - tpl_printf(vars, TPLADD, "RESHARE", "%d", cfg.cc_reshare); - - //CCcam Ignore Reshare - tpl_printf(vars, TPLADD, "TMP", "CCCIGNRSHRSELECTED%d", account->cccignorereshare); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - tpl_addVar(vars, TPLADD, "CFGIGNORERESHARE", - cfg.cc_ignore_reshare == 0 ? - "0 - use reshare level of Server" : "1 - use reshare level of Reader or User"); - - //CCcam Stealth Mode - tpl_printf(vars, TPLADD, "TMP", "CCCSTEALTHSELECTED%d", account->cccstealth); - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); - - tpl_addVar(vars, TPLADD, "STEALTH", cfg.cc_stealth ? "enable" : "disable"); -#endif - - //Failban - tpl_printf(vars, TPLADD, "FAILBAN", "%d", account->failban); - - if(!apicall) - { -#ifdef CS_CACHEEX_AIO - return tpl_getTpl(vars, "USEREDITAIO"); -#else - return tpl_getTpl(vars, "USEREDIT"); -#endif - } - else - { - return tpl_getTpl(vars, "APIUSEREDIT"); - } - -} - -static void webif_add_client_proto(struct templatevars *vars, struct s_client *cl, const char *proto, int8_t apicall) -{ - tpl_addVar(vars, TPLADDONCE, "CLIENTPROTO", ""); - tpl_addVar(vars, TPLADDONCE, "CLIENTPROTOSORT", ""); - tpl_addVar(vars, TPLADDONCE, "CLIENTPROTOTITLE", ""); - tpl_addVar(vars, TPLADDONCE, "PROTOICON", ""); - if(!cl) { return; } -#ifdef MODULE_NEWCAMD - if(streq(proto, "newcamd") && cl->typ == 'c') - { - tpl_printf(vars, TPLADD, "CLIENTPROTO", "%s (%s)", proto, newcamd_get_client_name(cl->ncd_client_id)); - tpl_printf(vars, TPLADD, "CLIENTPROTOSORT", "%s (%s)", proto, newcamd_get_client_name(cl->ncd_client_id)); - if(cfg.http_showpicons ) - { - char picon_name[32]; - snprintf(picon_name, sizeof(picon_name) / sizeof(char) - 1, "%s_%s", (char *)proto, newcamd_get_client_name(cl->ncd_client_id)); - if(picon_exists(picon_name)) - { - if (!apicall) - { - tpl_addVar(vars, TPLADD, "NCMDA", (char *)proto); - tpl_addVar(vars, TPLADD, "NCMDB", (char *)newcamd_get_client_name(cl->ncd_client_id)); - tpl_addVar(vars, TPLADD, "CLIENTPROTO", tpl_getTpl(vars, "PROTONEWCAMDPIC")); - } - else - { - tpl_printf(vars, TPLADDONCE, "PROTOICON", "%s_%s",(char *)proto, (char *)newcamd_get_client_name(cl->ncd_client_id)); - } - } - else - { - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "missing icon: IC_%s_%s.tpl", proto, newcamd_get_client_name(cl->ncd_client_id)); - } - } - return; - } -#endif -#ifdef MODULE_CCCAM - if(strncmp(proto, "cccam", 5) == 0) - { - struct cc_data *cc = cl->cc; - if(cc && *cc->remote_version && *cc->remote_build) - { - tpl_printf(vars, TPLADD, "CLIENTPROTO", "%s (%s-%s)", proto, cc->remote_version, cc->remote_build); - tpl_printf(vars, TPLADD, "CLIENTPROTOSORT", "%s (%s-%s)", proto, cc->remote_version, cc->remote_build); - if(cccam_client_multics_mode(cl)) - { - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "Multics, revision r%d", cc->multics_version[0] | (cc->multics_version[1] << 8)); - } - else - { -#endif -#ifdef CS_CACHEEX_AIO -#if defined(MODULE_CCCAM) && defined(CS_CACHEEX) - if(cl->reader && cl->reader->cacheex.feature_bitfield) - { - if(cl->reader->cacheex.feature_bitfield & 32) - { - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "%s [cx-aio %s]", (cc->extended_mode ? cc->remote_oscam : ""), cl->reader->cacheex.aio_version); - } - else if(cl->reader->cacheex.feature_bitfield) - { - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "%s [cx-aio < 9.2.3]", (cc->extended_mode ? cc->remote_oscam : "")); - } - } - else if(cl->account && cl->account->cacheex.feature_bitfield) - { - if(cl->account->cacheex.feature_bitfield & 32) - { - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "%s [cx-aio %s]", (cc->extended_mode ? cc->remote_oscam : ""), cl->account->cacheex.aio_version); - } - else if(cl->account->cacheex.feature_bitfield) - { - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "%s [cx-aio < 9.2.3]", (cc->extended_mode ? cc->remote_oscam : "")); - } - } - else - { -#endif -#endif -#ifdef MODULE_CCCAM - tpl_addVar(vars, TPLADD, "CLIENTPROTOTITLE", cc->extended_mode ? cc->remote_oscam : ""); -#endif -#ifdef CS_CACHEEX_AIO -#if defined(MODULE_CCCAM) && defined(CS_CACHEEX) - } -#endif -#endif -#ifdef MODULE_CCCAM - } - - if(cfg.http_showpicons) - { - char picon_name[32]; - - int8_t is_other_proto = 0; - if(cccam_client_multics_mode(cl)) { is_other_proto = 1; } - - switch(is_other_proto) - { - case 1: - snprintf(picon_name, sizeof(picon_name) / sizeof(char) - 1, "%s_r_%d", proto, cc->multics_version[0] | (cc->multics_version[1] << 8)); - if(picon_exists(picon_name)) - { - if (!apicall) - { - tpl_addVar(vars, TPLADD, "CCA", (char *)proto); - tpl_addVar(vars, TPLADD, "CCB", "r"); - tpl_printf(vars, TPLADD, "CCC", "%d", cc->multics_version[0] | (cc->multics_version[1] << 8)); - tpl_addVar(vars, TPLADD, "CCD", ""); - tpl_addVar(vars, TPLADD, "CLIENTPROTO", tpl_getTpl(vars, "PROTOCCCAMPIC")); - } - else - { - tpl_printf(vars, TPLADDONCE, "PROTOICON", "%s_r_%d",(char *)proto, cc->multics_version[0] | (cc->multics_version[1] << 8)); - } - } - else - { - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "Multics, revision r%d missing icon: IC_%s_r_%d.tpl", - cc->multics_version[0] | (cc->multics_version[1] << 8), proto, cc->multics_version[0] | (cc->multics_version[1] << 8)); - } - break; - - default: - snprintf(picon_name, sizeof(picon_name) / sizeof(char) - 1, "%s_%s_%s", proto, cc->remote_version, cc->remote_build); - if(picon_exists(picon_name)) - { - if (!apicall) - { - tpl_addVar(vars, TPLADD, "CCA", (char *)proto); - tpl_addVar(vars, TPLADD, "CCB", cc->remote_version); - tpl_addVar(vars, TPLADD, "CCC", cc->remote_build); -#ifdef CS_CACHEEX_AIO -#if defined(MODULE_CCCAM) && defined(CS_CACHEEX) - if(cl->reader && cl->reader->cacheex.feature_bitfield) - { - if(cl->reader->cacheex.feature_bitfield & 32) - { - tpl_printf(vars, TPLADD, "CCD", "%s [cx-aio %s]", (cc->extended_mode ? cc->remote_oscam : ""), cl->reader->cacheex.aio_version); - } - else if(cl->reader->cacheex.feature_bitfield) - { - tpl_printf(vars, TPLADD, "CCD", "%s [cx-aio < 9.2.3]", (cc->extended_mode ? cc->remote_oscam : "")); - } - } - else if(cl->account && cl->account->cacheex.feature_bitfield) - { - if(cl->account->cacheex.feature_bitfield & 32) - { - tpl_printf(vars, TPLADD, "CCD", "%s [cx-aio %s]", (cc->extended_mode ? cc->remote_oscam : ""), cl->account->cacheex.aio_version); - } - else if(cl->account->cacheex.feature_bitfield) - { - tpl_printf(vars, TPLADD, "CCD", "%s [cx-aio < 9.2.3]", (cc->extended_mode ? cc->remote_oscam : "")); - } - } - else - { -#endif -#endif - tpl_addVar(vars, TPLADD, "CCD", cc->extended_mode ? cc->remote_oscam : ""); -#ifdef CS_CACHEEX_AIO -#if defined(MODULE_CCCAM) && defined(CS_CACHEEX) - } -#endif -#endif - tpl_addVar(vars, TPLADD, "CLIENTPROTO", tpl_getTpl(vars, "PROTOCCCAMPIC")); - } - else - { - tpl_printf(vars, TPLADDONCE, "PROTOICON", "%s_%s_%s",(char *)proto, cc->remote_version, cc->remote_build); - } - } - else - { -#endif -#ifdef CS_CACHEEX_AIO -#if defined(MODULE_CCCAM) && defined(CS_CACHEEX) - if(cl->reader && cl->reader->cacheex.feature_bitfield) - { - if(cl->reader->cacheex.feature_bitfield & 32) - { - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "%s [cx-aio %s] missing icon: IC_%s_%s_%s.tpl", (cc->extended_mode ? cc->remote_oscam : ""), cl->reader->cacheex.aio_version, proto, cc->remote_version, cc->remote_build); - } - else if(cl->reader->cacheex.feature_bitfield) - { - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "%s [cx-aio < 9.2.3] missing icon: IC_%s_%s_%s.tpl", (cc->extended_mode ? cc->remote_oscam : ""), proto, cc->remote_version, cc->remote_build); - } - } - else if(cl->account && cl->account->cacheex.feature_bitfield) - { - if(cl->account->cacheex.feature_bitfield & 32) - { - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "%s [cx-aio %s] missing icon: IC_%s_%s_%s.tpl", (cc->extended_mode ? cc->remote_oscam : ""), cl->account->cacheex.aio_version, proto, cc->remote_version, cc->remote_build); - } - else if(cl->account->cacheex.feature_bitfield) - { - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "%s [cx-aio < 9.2.3] missing icon: IC_%s_%s_%s.tpl", (cc->extended_mode ? cc->remote_oscam : ""), proto, cc->remote_version, cc->remote_build); - } - } - else - { -#endif -#endif -#ifdef MODULE_CCCAM - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "%s missing icon: IC_%s_%s_%s.tpl", - cc->extended_mode ? cc->remote_oscam : "", proto, cc->remote_version, cc->remote_build); -#ifdef CS_CACHEEX_AIO -#if defined(MODULE_CCCAM) && defined(CS_CACHEEX) - } -#endif -#endif - } - break; - } - } - } - return; - } -#endif -#ifdef CS_CACHEEX_AIO -#if (defined(MODULE_CAMD35) || defined(MODULE_CAMD35_TCP)) && defined(CS_CACHEEX) - if(strncmp(proto, "cs3", 3) == 0) - { - tpl_addVar(vars, TPLADDONCE, "CLIENTPROTO", (char *)proto); - - char aiover[32]; - aiover[0] = '\0'; - - if(cl->account && cl->cacheex_aio_checked) - { - if(cl->account->cacheex.feature_bitfield & 32) - { - snprintf(aiover, sizeof(aiover) / sizeof(char) -1, "%s", cl->account->cacheex.aio_version); - tpl_addVar(vars, TPLADD, "CLIENTPROTOTITLE", aiover); - } - else if(cl->account->cacheex.feature_bitfield) - { - snprintf(aiover, sizeof(aiover) / sizeof(char) -1, "%s", "[cx-aio: < 9.2.3]"); - tpl_addVar(vars, TPLADD, "CLIENTPROTOTITLE", aiover); - } - else - { - tpl_addVar(vars, TPLADD, "CLIENTPROTOTITLE", ""); - } - } - - if(cl->reader && cl->cacheex_aio_checked) - { - if(cl->reader->cacheex.feature_bitfield & 32) - { - snprintf(aiover, sizeof(aiover) / sizeof(char) -1, "%s", cl->reader->cacheex.aio_version); - tpl_addVar(vars, TPLADD, "CLIENTPROTOTITLE", aiover); - } - else if(cl->reader->cacheex.feature_bitfield) - { - snprintf(aiover, sizeof(aiover) / sizeof(char) -1, "%s", "[cx-aio: < 9.2.3]"); - tpl_addVar(vars, TPLADD, "CLIENTPROTOTITLE", aiover); - } - else - { - tpl_addVar(vars, TPLADD, "CLIENTPROTOTITLE", ""); - } - } - - if(cfg.http_showpicons) - { - tpl_addVar(vars, TPLADDONCE, "CLIENTPROTO", (char *)proto); - - char picon_name[32]; - snprintf(picon_name, sizeof(picon_name) / sizeof(char) - 1, "%s", proto); - if(picon_exists(picon_name)) - { - if (!apicall) - { - tpl_addVar(vars, TPLADD, "CAMD3A", (char *)proto); - if(aiover[0] == '\0') - tpl_addVar(vars, TPLADD, "AIOVER", ""); - else - tpl_printf(vars, TPLADD, "AIOVER", "[cx-aio %s]", aiover); - - tpl_addVar(vars, TPLADD, "CLIENTPROTO", tpl_getTpl(vars, "PROTOCAMD3AIOPIC")); - } - else - { - tpl_printf(vars, TPLADDONCE, "PROTOICON", "%s",(char *)proto); - } - } - else - { - if(cl->account && cl->cacheex_aio_checked) - { - if(cl->account->cacheex.feature_bitfield & 32) - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "missing icon: IC_%s.tpl [cx-aio %s]", proto, cl->account->cacheex.aio_version); - else if(cl->account->cacheex.feature_bitfield) - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "missing icon: IC_%s.tpl [cx-aio < 9.2.3]", proto); - else - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "missing icon: IC_%s.tpl", proto); - } - - if(cl->reader && cl->cacheex_aio_checked) - { - if(cl->reader->cacheex.feature_bitfield & 32) - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "missing icon: IC_%s.tpl [cx-aio %s]", proto, cl->reader->cacheex.aio_version); - else if(cl->reader->cacheex.feature_bitfield) - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "missing icon: IC_%s.tpl [cx-aio < 9.2.3]", proto); - else - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "missing icon: IC_%s.tpl", proto); - } - } - } - return; - } -#endif -#endif - -#ifdef HAVE_DVBAPI - if(streq(proto, "dvbapi") && cl->typ == 'c' && strcmp(dvbapi_get_client_name(), "")) - { - if (!apicall) - tpl_printf(vars, TPLADD, "CLIENTPROTO", "%sclient: %s
protocol version: %d
", proto, dvbapi_get_client_name(), dvbapi_get_client_proto_version()); - else - tpl_printf(vars, TPLADD, "CLIENTPROTO", "%s (client: %s, protocol version: %d)", proto, dvbapi_get_client_name(), dvbapi_get_client_proto_version()); - tpl_printf(vars, TPLADD, "CLIENTPROTOSORT", "%s", proto); - return; - } -#endif - tpl_addVar(vars, TPLADDONCE, "CLIENTPROTO", (char *)proto); - tpl_addVar(vars, TPLADDONCE, "CLIENTPROTOSORT", (char *)proto); - if(cfg.http_showpicons) - { - char picon_name[32]; - snprintf(picon_name, sizeof(picon_name) / sizeof(char) - 1, "%s", proto); - if(picon_exists(picon_name)) - { - if (!apicall) - { - tpl_addVar(vars, TPLADD, "OTHER", (char *)proto); - tpl_addVar(vars, TPLADD, "CLIENTPROTO", tpl_getTpl(vars, "PROTOOTHERPIC")); - } - else - { - tpl_printf(vars, TPLADDONCE, "PROTOICON", "%s",(char *)proto); - } - } - else - { - tpl_printf(vars, TPLADD, "CLIENTPROTOTITLE", "missing icon: IC_%s.tpl", proto); - } - } -} - -static void kill_account_thread(struct s_auth *account) -{ - struct s_client *cl; - for(cl = first_client->next; cl ; cl = cl->next) - { - if(cl->account == account) - { - if(get_module(cl)->type & MOD_CONN_NET) - { - kill_thread(cl); - } - else - { - cl->account = first_client->account; - } - } - } -} - -static char *send_oscam_user_config(struct templatevars *vars, struct uriparams *params, int32_t apicall) -{ - struct s_auth *account; - struct s_client *cl; - char *user = getParam(params, "user"); - int32_t found = 0; - uint8_t md5tmp[MD5_DIGEST_LENGTH]; - - if(!apicall) - { - setActiveMenu(vars, MNU_USERS); - } - if(strcmp(getParam(params, "action"), "reinit") == 0) - { - if(!cfg.http_readonly) - { refresh_oscam(REFR_ACCOUNTS); } - } - if(strcmp(getParam(params, "action"), "delete") == 0) - { - if(cfg.http_readonly) - { - tpl_addMsg(vars, "WebIf is in readonly mode. No deletion will be made!"); - } - else - { - struct s_auth *account_prev = NULL; - - for(account = cfg.account; (account); account = account->next) - { - if(strcmp(account->usr, user) == 0) - { - if(account_prev == NULL) - { cfg.account = account->next; } - else - { account_prev->next = account->next; } - ll_clear(account->aureader_list); - kill_account_thread(account); - add_garbage(account); - found = 1; - break; - } - account_prev = account; - } - if(found > 0) - { - if(write_userdb() != 0) { tpl_addMsg(vars, "Write Config failed!"); } - } - else { tpl_addMsg(vars, "Sorry but the specified user doesn't exist. No deletion will be made!"); } - } - } - - if((strcmp(getParam(params, "action"), "disable") == 0) || (strcmp(getParam(params, "action"), "enable") == 0)) - { - account = get_account_by_name(getParam(params, "user")); - if(account) - { - if(strcmp(getParam(params, "action"), "disable") == 0) - { - account->disabled = 1; - kill_account_thread(account); - } - else - { account->disabled = 0; } - if(write_userdb() != 0) { tpl_addMsg(vars, "Write Config failed!"); } - } - else - { - tpl_addMsg(vars, "Sorry but the specified user doesn't exist. No deletion will be made!"); - } - } - - if(strcmp(getParam(params, "action"), "resetstats") == 0) - { - account = get_account_by_name(getParam(params, "user")); - if(account) { clear_account_stats(account); } - } - - if(strcmp(getParam(params, "action"), "resetuserstats") == 0) - { - clear_info_clients_stats(); - } - - if(strcmp(getParam(params, "action"), "resetreaderstats") == 0) - { - clear_info_readers_stats(); - } - - if(strcmp(getParam(params, "action"), "resetalluserstats") == 0) - { - clear_all_account_stats(); - } - - if((strcmp(getParam(params, "part"), "adduser") == 0) && (!cfg.http_readonly)) - { - tpl_addVar(vars, TPLAPPEND, "NEWUSERFORM", tpl_getTpl(vars, "ADDNEWUSER")); - } - - /* List accounts*/ - char *status, *expired, *classname, *lastchan; - time_t now = time((time_t *)0); - int32_t isec = 0, chsec = 0; - - char *filter = NULL; - int32_t clientcount = 0; - if(apicall) - { - filter = getParam(params, "label"); - } - int8_t grp_set = 0; - int8_t expdate_set = 0; - int32_t total_users = 0; - int32_t disabled_users = 0; - int32_t expired_users = 0; - int32_t expired_or_disabled_users = 0; - int32_t connected_users = 0; - int32_t online_users = 0; - int32_t casc_users = 0; - int32_t casc_users2 = 0; - int32_t n_request = 0; - int existing_insert = 0; - - for(account = cfg.account; (account); account = account->next) - { - if(account->expirationdate){ - expdate_set = 1; - } - - if(account->next){ - if(account->grp != account->next->grp){ - grp_set = 1; - } - } - if(expdate_set && grp_set) - break; - } - - for(account = cfg.account; (account); account = account->next) - { - //clear for next client - total_users++; - isactive = 1; - - status = "offline"; - classname = "offline"; - isec = 0; - chsec = 0; - - //reset caid/srevid template variables - tpl_addVar(vars, TPLADD, "CLIENTCAID", ""); - tpl_addVar(vars, TPLADD, "CLIENTPROVID", ""); - tpl_addVar(vars, TPLADD, "CLIENTSRVID", ""); - tpl_addVar(vars, TPLADD, "LASTCHANNEL", ""); - tpl_addVar(vars, TPLADD, "LASTCHANNELSORT", ""); - tpl_addVar(vars, TPLADD, "USERMD5", ""); - tpl_addVar(vars, TPLADD, "CWLASTRESPONSET", ""); - tpl_addVar(vars, TPLADD, "CWLASTRESPONSETMS", ""); - tpl_addVar(vars, TPLADD, "CLIENTIP", ""); - tpl_addVar(vars, TPLADD, "LASTCHANNELTITLE", ""); - tpl_addVar(vars, TPLADD, "LASTCHANNELSORT", ""); - tpl_addVar(vars, TPLADD, "CLIENTTIMEONCHANNELAPI", ""); - tpl_addVar(vars, TPLADD, "CLIENTTIMEONCHANNEL", ""); - tpl_addVar(vars, TPLADD, "CLIENTTIMETOSLEEP", ""); - tpl_addVar(vars, TPLADD, "CLIENTTIMETOSLEEPAPI", ""); - tpl_addVar(vars, TPLADD, "IDLESECS", ""); - tpl_addVar(vars, TPLADD, "UNOTIFY", ""); - - if(account->expirationdate && account->expirationdate < now) - { - expired = " (expired)"; - classname = "expired"; - expired_users++; - isactive = 0; - } - else - { - expired = ""; - } - - if(account->disabled != 0) - { - expired = " (disabled)"; - classname = "disabled"; - tpl_addVar(vars, TPLADD, "SWITCHICO", "image?i=ICENA"); - tpl_addVar(vars, TPLADD, "SWITCHTITLE", "Enable"); - tpl_addVar(vars, TPLADD, "SWITCH", "enable"); - disabled_users++; - isactive = 0; - } - else - { - tpl_addVar(vars, TPLADD, "SWITCHICO", "image?i=ICDIS"); - tpl_addVar(vars, TPLADD, "SWITCHTITLE", "Disable"); - tpl_addVar(vars, TPLADD, "SWITCH", "disable"); - } - if((account->expirationdate && account->expirationdate < now)||account->disabled != 0) - { - expired_or_disabled_users++; - } - - int32_t lastresponsetm = 0, latestactivity = 0; - const char *proto = ""; - double cwrate = 0.0, cwrate2 = 0.0; - - //search account in active clients - isactive = 0; - int16_t nrclients = 0; - struct s_client *latestclient = NULL; - for(cl = first_client->next; cl ; cl = cl->next) - { - if(cl->account && !strcmp(cl->account->usr, account->usr)) - { - if(cl->lastecm > latestactivity || cl->login > latestactivity) - { - if(cl->lastecm > cl->login) { latestactivity = cl->lastecm; } - else { latestactivity = cl->login; } - latestclient = cl; - } - nrclients++; - } - } - if(account->cwfound + account->cwnot + account->cwcache > 0) - { - cwrate = now - account->firstlogin; - cwrate /= (account->cwfound + account->cwnot + account->cwcache); - } - - casc_users = 0; - casc_users2 = 0; - int8_t conn = 0; - if(latestclient != NULL) - { - char channame[CS_SERVICENAME_SIZE]; - status = (!apicall) ? "connected" : "connected"; - if(account->expirationdate && account->expirationdate < now) { classname = "expired"; } - else { classname = "connected";conn = 1; } - - proto = client_get_proto(latestclient); - int clientcaid = latestclient->last_caid; - int clientsrvid = latestclient->last_srvid; - int clientprovid = latestclient->last_provid; - tpl_printf(vars, TPLADD, "CLIENTCAID", "%04X", clientcaid); - tpl_printf(vars, TPLADD, "CLIENTPROVID", "%06X", clientprovid); - tpl_printf(vars, TPLADD, "CLIENTSRVID", "%04X", clientsrvid); - - if(clientsrvid != NO_SRVID_VALUE || clientcaid != NO_CAID_VALUE) - { - lastchan = xml_encode(vars, get_servicename(latestclient, clientsrvid, clientprovid, clientcaid, channame, sizeof(channame))); - tpl_addVar(vars, TPLADD, "LASTCHANNELSORT", lastchan); - } - else - { - lastchan = ""; - tpl_addVar(vars, TPLADD, "LASTCHANNELSORT", "~~~~~"); - } - - tpl_addVar(vars, TPLADDONCE, "LASTCHANNEL", lastchan); - tpl_addVar(vars, TPLADD, "LASTCHANNELTITLE", lastchan); - - if(cfg.http_showpicons ) - { - char picon_name[128]; - char picon_channame[128]; - int8_t picon_ok = 0; - - get_picon_servicename_or_null(latestclient, clientsrvid, clientprovid, clientcaid, picon_channame, sizeof(picon_channame)); - if(picon_channame[0]) - { - snprintf(picon_name, sizeof(picon_name) / sizeof(char), "%s", picon_channame); - picon_ok = picon_exists(picon_name); - - if(!picon_ok && picon_servicename_remve_hd(picon_channame, sizeof(picon_channame))) - { - snprintf(picon_name, sizeof(picon_name) / sizeof(char), "%s", picon_channame); - picon_ok = picon_exists(picon_name); - } - } - if(!picon_ok) - { - snprintf(picon_name, sizeof(picon_name) / sizeof(char), "%04X_%06X_%04X", clientcaid, clientprovid, clientsrvid); - picon_ok = picon_exists(picon_name); - } - if(!picon_ok) - { - snprintf(picon_name, sizeof(picon_name) / sizeof(char), "%04X_%04X", clientcaid, clientsrvid); - picon_ok = picon_exists(picon_name); - } - if(!picon_ok) - { - snprintf(picon_name, sizeof(picon_name) / sizeof(char), "0000_%04X", clientsrvid); - picon_ok = picon_exists(picon_name); - } - if(picon_ok) - { - tpl_addVar(vars, TPLADDONCE, "LCA", picon_name); - tpl_addVar(vars, TPLADDONCE, "LCB", lastchan); - if(!apicall) - { - tpl_addVar(vars, TPLADDONCE, "LASTCHANNEL", tpl_getTpl(vars, "USERCONFIGLASTCHANEL")); - } - } - else - { - tpl_printf(vars, TPLADD, "LASTCHANNELTITLE", "missing icon: IC_%s.tpl", picon_name); - } - } - - lastresponsetm = latestclient->cwlastresptime; - if(IP_ISSET(latestclient->ip)) - { tpl_addVar(vars, TPLADD, "CLIENTIP", cs_inet_ntoa(latestclient->ip)); } - else if(latestclient->login > latestclient->logout) - { tpl_addVar(vars, TPLADD, "CLIENTIP", "camd.socket"); } - else - { tpl_addVar(vars, TPLADD, "CLIENTIP", ""); } - connected_users++; - casc_users = ll_count(latestclient->cascadeusers); - LL_ITER it = ll_iter_create(latestclient->cascadeusers); - struct s_cascadeuser *cu; - while((cu = ll_iter_next(&it))) - { - if(cu->cwrate > 0) - { casc_users2++; } - } - if(latestactivity > 0) - { - isec = now - latestactivity; - chsec = latestclient->lastswitch ? now - latestclient->lastswitch : 0; - if(isec < cfg.hideclient_to) - { - isactive = 1; - status = (!apicall) ? "online" : "online"; - if(account->expirationdate && account->expirationdate < now) { classname = "expired"; } - else { classname = "online"; } - if(latestclient->cwfound + latestclient->cwnot + latestclient->cwcache > 0) - { - cwrate2 = now - latestclient->login; - cwrate2 /= (latestclient->cwfound + latestclient->cwnot + latestclient->cwcache); - tpl_printf(vars, TPLADDONCE, "CWRATE2", " (%.2f)", cwrate2); - online_users++; - } - } - } - } - - n_request = 0; - if(latestclient != NULL){ - n_request = latestclient->n_request[0]; - } - - tpl_addVar(vars, TPLADD, "EXPIREVIEW", expdate_set ? "" : "exp"); - tpl_addVar(vars, TPLADD, "GRPVIEW", grp_set ? "" : "grp"); -#ifdef CS_ANTICASC - tpl_addVar(vars, TPLADD, "ANTICASCVIEW", cfg.ac_enabled ? "" : "acas"); -#endif - tpl_printf(vars, TPLADD, "CWOK", PRINTF_LOCAL_D, account->cwfound); - tpl_printf(vars, TPLADD, "CWNOK", PRINTF_LOCAL_D, account->cwnot); - tpl_printf(vars, TPLADD, "CWIGN", PRINTF_LOCAL_D, account->cwignored); - tpl_printf(vars, TPLADD, "CWTOUT", PRINTF_LOCAL_D, account->cwtout); -#ifdef CW_CYCLE_CHECK - tpl_addVar(vars, TPLADD, "CWCCYCVIEW", cfg.cwcycle_check_enable ? "" : "cwc"); - tpl_printf(vars, TPLADD, "CWCYCLECHECKED", "%d", account->cwcycledchecked); - tpl_printf(vars, TPLADD, "CWCYCLEOK", "%d", account->cwcycledok); - tpl_printf(vars, TPLADD, "CWCYCLENOK", "%d", account->cwcyclednok); - tpl_printf(vars, TPLADD, "CWCYCLEIGN", "%d", account->cwcycledign); -#endif - tpl_printf(vars, TPLADD, "CWCACHE", PRINTF_LOCAL_D, account->cwcache); - tpl_printf(vars, TPLADD, "CWTUN", PRINTF_LOCAL_D, account->cwtun); - tpl_printf(vars, TPLADD, "EMMOK", PRINTF_LOCAL_D, account->emmok); - tpl_printf(vars, TPLADD, "EMMNOK", PRINTF_LOCAL_D, account->emmnok); - tpl_printf(vars, TPLADD, "CWRATE", "%.2f", cwrate); - tpl_printf(vars, TPLADD, "CASCUSERS", "%d", casc_users); - tpl_printf(vars, TPLADD, "CASCUSERS2", "%d", casc_users2); - tpl_printf(vars, TPLADD, "CASCUSERSCOMB", "%d/%d", casc_users, casc_users2); - tpl_printf(vars, TPLADD, "N_REQUEST_MIN", "%d", n_request); - - if(isactive > 0 || conn > 0) - { - if(casc_users+casc_users2>0) - { - tpl_printf(vars, TPLADD, "CWLASTRESPONSET", "%d", lastresponsetm); - tpl_printf(vars, TPLADD, "CWLASTRESPONSETMS", PRINTF_LOCAL_D " ms", lastresponsetm); - } - tpl_addVar(vars, TPLADD, "IDLESECS", sec2timeformat(vars, isec)); - } - - if(isactive > 0) - { - tpl_printf(vars, TPLADD, "CLIENTTIMEONCHANNELAPI", "%d", chsec); - tpl_addVar(vars, TPLADD, "CLIENTTIMEONCHANNEL", sec2timeformat(vars, chsec)); - - if(account->tosleep) - { - if(account->tosleep >0){ - tpl_printf(vars, TPLADD, "CLIENTTIMETOSLEEP", "Sleeping in %d minutes", account->tosleep - (chsec / 60)); - } else { - tpl_addVar(vars, TPLADD, "CLIENTTIMETOSLEEP", "Sleeping"); - } - tpl_printf(vars, TPLADD, "CLIENTTIMETOSLEEPAPI", "%d", account->tosleep - (chsec / 60)); - } else { - tpl_addVar(vars, TPLADD, "CLIENTTIMETOSLEEPAPI", "undefined"); - } - } -#ifdef CS_CACHEEX_AIO -#if defined(MODULE_CAMD35) || defined (MODULE_CAMD35_TCP) - if(latestclient != NULL && (latestclient->account->cacheex.feature_bitfield || latestclient->c35_extmode > 1)) -#else - if(latestclient != NULL && (latestclient->account->cacheex.feature_bitfield)) -#endif - { - const char *aio_suffix = " (cx-aio)"; - char *new_proto; - if(cs_malloc(&new_proto, cs_strlen(proto)+cs_strlen(aio_suffix)+1)) { - if (!cs_strncat(new_proto, (char *)proto, cs_strlen(proto)+cs_strlen(aio_suffix)+1)) { - cs_log("FIXME!"); - } - if (cs_strncat(new_proto, (char *)aio_suffix, cs_strlen(proto)+cs_strlen(aio_suffix)+1)) { - webif_add_client_proto(vars, latestclient, (const char *)new_proto, apicall); - } else { - cs_log("FIXME!"); - } - free(new_proto); - } - } else { -#endif - webif_add_client_proto(vars, latestclient, proto, apicall); -#ifdef CS_CACHEEX_AIO - } -#endif - - tpl_addVar(vars, TPLADD, "CLASSNAME", classname); - MD5((uint8_t *)account->usr, cs_strlen(account->usr), md5tmp); - int z; - tpl_addVar(vars, TPLADD, "USERMD5","id_"); - for (z = 0; z < MD5_DIGEST_LENGTH; z++) - { - tpl_printf(vars, TPLAPPEND, "USERMD5", "%02x", md5tmp[z]); - } - tpl_addVar(vars, TPLADD, "USERNAME", xml_encode(vars, account->usr)); - tpl_addVar(vars, TPLADD, "USERNAMEENC", urlencode(vars, account->usr)); - if(!existing_insert) - { - tpl_printf(vars, TPLADD, "EXISTING_INS", "'%s'", urlencode(vars, account->usr)); - existing_insert++; - }else - { - tpl_printf(vars, TPLAPPEND, "EXISTING_INS", ",'%s'", urlencode(vars, account->usr)); - } - - if(account->description) - tpl_printf(vars, TPLADD, "DESCRIPTION","%s(%s)",!apicall?" ":"",xml_encode(vars, account->description)); - else - tpl_addVar(vars, TPLADD, "DESCRIPTION", ""); - - if(cfg.http_showpicons && !apicall) - tpl_addVar(vars, TPLADD, "USERBIT", tpl_getTpl(vars, picon_exists(xml_encode(vars, account->usr)) ? "USERICON" : "USERNOICON")); - else - tpl_addVar(vars, TPLADD, "USERBIT", tpl_getTpl(vars, "USERLABEL")); - - char *value = mk_t_group(account->grp); - tpl_addVar(vars, TPLADD, "GROUPS", value); - free_mk_t(value); - tpl_addVar(vars, TPLADD, "STATUS", status); - tpl_addVar(vars, TPLAPPEND, "STATUS", expired); - - if(nrclients > 1) - { - tpl_printf(vars, TPLADD, "UNOTIFY", "%d", nrclients); - tpl_addVar(vars, TPLADDONCE, "CLIENTCOUNTNOTIFIER", tpl_getTpl(vars, "CLIENTCOUNTNOTIFIERBIT")); - } - - //Expirationdate - struct tm timeinfo; - cs_gmtime_r(&account->expirationdate, &timeinfo); - char buf [80]; - strftime(buf, 80, "%Y-%m-%d", &timeinfo); - if(strcmp(buf, "1970-01-01")) { tpl_addVar(vars, TPLADD, "EXPDATE", buf); } - else { tpl_addVar(vars, TPLADD, "EXPDATE", ""); } - - // append row to table template - if(!apicall) - { tpl_addVar(vars, TPLAPPEND, "USERCONFIGS", tpl_getTpl(vars, "USERCONFIGLISTBIT")); } - else if(!filter || strcmp(filter, account->usr) == 0 || strcmp(filter, "all") == 0 || cs_strlen(filter) == 0) - { - if(apicall == 1){ - tpl_addVar(vars, TPLAPPEND, "APIUSERCONFIGS", tpl_getTpl(vars, "APIUSERCONFIGLISTBIT")); - } else if (apicall == 2){ - tpl_printf(vars, TPLADD, "JSONDELIMITER", "%s", (total_users > 1)?",":""); - tpl_addVar(vars, TPLAPPEND, "APIUSERCONFIGS", tpl_getTpl(vars, "JSONUSERBIT")); - } - ++clientcount; - } - } - - tpl_printf(vars, TPLADD, "TOTAL_USERS", "%d", total_users); - tpl_printf(vars, TPLADD, "TOTAL_DISABLED", "%d", disabled_users); - tpl_printf(vars, TPLADD, "TOTAL_EXPIRED", "%d", expired_users); - tpl_printf(vars, TPLADD, "TOTAL_ACTIVE", "%d", total_users - expired_or_disabled_users); - tpl_printf(vars, TPLADD, "TOTAL_CONNECTED", "%d", connected_users); - tpl_printf(vars, TPLADD, "TOTAL_ONLINE", "%d", online_users); - - //CM info - tpl_addVar(vars, TPLADD, "DISPLAYREADERINFO", "hidden"); // no readerinfo in users - set_ecm_info(vars); - - if(!apicall) - { return tpl_getTpl(vars, "USERCONFIGLIST"); } - else - { - if(!filter || clientcount > 0) - { - return tpl_getTpl(vars, (apicall==1)?"APIUSERCONFIGLIST":"JSONUSER"); - } - else - { - tpl_printf(vars, TPLADD, "APIERRORMESSAGE", "Invalid client %s", xml_encode(vars, filter)); - return tpl_getTpl(vars, "APIERROR"); - } - } - -} - -#define ENTITLEMENT_PAGE_SIZE 500 - -#ifdef MODULE_CCCAM -static void print_cards(struct templatevars *vars, struct uriparams *params, struct cc_card **cardarray, int32_t cardsize, - int8_t show_global_list, struct s_reader *rdr, int32_t offset, int32_t apicall) -{ - if(cardarray) - { - uint8_t serbuf[8]; - int32_t i, count = 0; - char provname[83]; - struct cc_card *card; - int32_t cardcount = 0; - int32_t providercount = 0; - int32_t nodecount = 0; - - char *provider = ""; - - // @todo alno: sort by click, 0=ascending, 1=descending (maybe two buttons or reverse on second click) - for(i = offset; i < cardsize; ++i) - { - card = cardarray[i]; - if(count == ENTITLEMENT_PAGE_SIZE) - { break; } - count++; - - if(!apicall) - { - if(show_global_list) - { rdr = card->origin_reader; } - if(rdr) - { tpl_printf(vars, TPLADD, "HOST", "%s:%d", xml_encode(vars, rdr->device), rdr->r_port); } - tpl_printf(vars, TPLADD, "CAID", "%04X", card->caid); - tpl_printf(vars, TPLADD, "CARDTYPE", "%02X", card->card_type); - } - else - { - tpl_printf(vars, TPLADD, "APICARDNUMBER", "%d", cardcount); - tpl_printf(vars, TPLADD, "APICAID", "%04X", card->caid); - tpl_printf(vars, TPLADD, "APICARDTYPE", "%02X", card->card_type); - } - - if(cc_UA_valid(card->hexserial)) //Add UA: - { - cc_UA_cccam2oscam(card->hexserial, serbuf, card->caid); - char tmp[20]; - tpl_printf(vars, TPLAPPEND, "HOST", "
\nUA_OSCam:%s", cs_hexdump(0, serbuf, 8, tmp, 20)); - tpl_printf(vars, TPLAPPEND, "HOST", "
\nUA_CCcam:%s", cs_hexdump(0, card->hexserial, 8, tmp, 20)); - } - if(!apicall) - { - int32_t n; - char channame[CS_SERVICENAME_SIZE]; - int8_t sidname = 0; - LL_ITER its = ll_iter_create(card->goodsids); - struct cc_srvid *srv; - n = 0; - if(strcmp(getParam(params, "button"), "Show detail list") == 0) - { sidname = 1; } - - tpl_addVar(vars, TPLADD, "SERVICESGOOD", ""); - while((srv = ll_iter_next(&its))) - { - if(sidname) - { - tpl_printf(vars, TPLAPPEND, "SERVICESGOOD", "%04X - %s
", srv->sid, xml_encode(vars, get_servicename(cur_client(), srv->sid, 0, card->caid, channame, sizeof(channame)))); - } else { - tpl_printf(vars, TPLAPPEND, "SERVICESGOOD", "%04X%s", srv->sid, ++n % 10 == 0 ? "
\n" : " "); - } - } - - its = ll_iter_create(card->badsids); - n = 0; - tpl_addVar(vars, TPLADD, "SERVICESBAD", ""); - while((srv = ll_iter_next(&its))) - { - if(sidname) - { - tpl_printf(vars, TPLAPPEND, "SERVICESBAD", "%04X - %s
", srv->sid, xml_encode(vars, get_servicename(cur_client(), srv->sid, 0, card->caid, channame, sizeof(channame)))); - } else { - tpl_printf(vars, TPLAPPEND, "SERVICESBAD", "%04X%s", srv->sid, ++n % 10 == 0 ? "
\n" : " "); - } - } - } - - tpl_addVar(vars, TPLADD, "SYSTEM", get_cardsystem_desc_by_caid(card->caid)); - - tpl_printf(vars, TPLADD, "SHAREID", "%08X", card->id); - tpl_printf(vars, TPLADD, "REMOTEID", "%08X", card->remote_id); - tpl_printf(vars, TPLADD, "UPHOPS", "%d", card->hop); - tpl_printf(vars, TPLADD, "MAXDOWN", "%d", card->reshare); - - LL_ITER pit = ll_iter_create(card->providers); - struct cc_provider *prov; - - providercount = 0; - - if(!apicall) - { tpl_addVar(vars, TPLADD, "PROVIDERS", ""); } - else - { tpl_addVar(vars, TPLADD, "PROVIDERLIST", ""); } - - while((prov = ll_iter_next(&pit))) - { - provider = xml_encode(vars, get_provider(prov->prov, card->caid, provname, sizeof(provname))); - - if(!apicall) - { - if(prov->sa[0] || prov->sa[1] || prov->sa[2] || prov->sa[3]) - { - tpl_printf(vars, TPLAPPEND, "PROVIDERS", "%s SA:%02X%02X%02X%02X
\n", provider, prov->sa[0], prov->sa[1], prov->sa[2], prov->sa[3]); - } - else - { - tpl_printf(vars, TPLAPPEND, "PROVIDERS", "%s
\n", provider); - } - } - else - { - if(prov->sa[0] || prov->sa[1] || prov->sa[2] || prov->sa[3]) - { tpl_printf(vars, TPLADD, "APIPROVIDERSA", "%02X%02X%02X%02X", prov->sa[0], prov->sa[1], prov->sa[2], prov->sa[3]); } - else - { tpl_addVar(vars, TPLADD, "APIPROVIDERSA", ""); } - tpl_printf(vars, TPLADD, "APIPROVIDERCAID", "%04X", card->caid); - tpl_printf(vars, TPLADD, "APIPROVIDERPROVID", "%06X", prov->prov); - tpl_printf(vars, TPLADD, "APIPROVIDERNUMBER", "%d", providercount); - tpl_addVar(vars, TPLADD, "APIPROVIDERNAME", xml_encode(vars, provider)); - tpl_addVar(vars, TPLAPPEND, "PROVIDERLIST", tpl_getTpl(vars, "APICCCAMCARDPROVIDERBIT")); - - } - providercount++; - tpl_printf(vars, TPLADD, "APITOTALPROVIDERS", "%d", providercount); - } - - LL_ITER nit = ll_iter_create(card->remote_nodes); - uint8_t *node; - - nodecount = 0; - if(!apicall) { tpl_addVar(vars, TPLADD, "NODES", ""); } - else { tpl_addVar(vars, TPLADD, "NODELIST", ""); } - - while((node = ll_iter_next(&nit))) - { - - if(!apicall) - { - tpl_printf(vars, TPLAPPEND, "NODES", "%02X%02X%02X%02X%02X%02X%02X%02X
\n", - node[0], node[1], node[2], node[3], node[4], node[5], node[6], node[7]); - } - else - { - tpl_printf(vars, TPLADD, "APINODE", "%02X%02X%02X%02X%02X%02X%02X%02X", node[0], node[1], node[2], node[3], node[4], node[5], node[6], node[7]); - tpl_printf(vars, TPLADD, "APINODENUMBER", "%d", nodecount); - tpl_addVar(vars, TPLAPPEND, "NODELIST", tpl_getTpl(vars, "APICCCAMCARDNODEBIT")); - } - nodecount++; - tpl_printf(vars, TPLADD, "APITOTALNODES", "%d", nodecount); - } - - if(!apicall) - { tpl_addVar(vars, TPLAPPEND, "CCCAMSTATSENTRY", tpl_getTpl(vars, "ENTITLEMENTCCCAMENTRYBIT")); } - else - { tpl_addVar(vars, TPLAPPEND, "CARDLIST", tpl_getTpl(vars, "APICCCAMCARDBIT")); } - - cardcount++; - } - // set previous Link if needed - if(offset >= ENTITLEMENT_PAGE_SIZE) - { - tpl_printf(vars, TPLAPPEND, "CONTROLS", " << PREVIOUS < ", - offset - ENTITLEMENT_PAGE_SIZE, - getParam(params, "globallist"), - urlencode(vars, getParam(params, "label"))); - } - - // set next link if needed - if(cardsize > count && offset < cardsize) - { - tpl_printf(vars, TPLAPPEND, "CONTROLS", " > NEXT >> ", - offset + ENTITLEMENT_PAGE_SIZE, - getParam(params, "globallist"), - urlencode(vars, getParam(params, "label"))); - } - - if(!apicall) - { - tpl_printf(vars, TPLADD, "TOTALS", "card count=%d", cardsize); - tpl_addVar(vars, TPLADD, "ENTITLEMENTCONTENT", tpl_getTpl(vars, "ENTITLEMENTCCCAMBIT")); - } - else - { - tpl_printf(vars, TPLADD, "APITOTALCARDS", "%d", cardsize); - } - - } - else - { - if(!apicall) - { - tpl_addVar(vars, TPLADD, "ENTITLEMENTCONTENT", tpl_getTpl(vars, "ENTITLEMENTGENERICBIT")); - tpl_addVar(vars, TPLADD, "LOGHISTORY", "no cards found
\n"); - } - else - { - tpl_printf(vars, TPLADD, "APITOTALCARDS", "%d", 0); - } - } - -} -#endif - -static char *send_oscam_entitlement(struct templatevars *vars, struct uriparams *params, int32_t apicall) -{ - if(!apicall) { setActiveMenu(vars, MNU_READERS); } - char *reader_ = getParam(params, "label"); -#ifdef MODULE_CCCAM -#ifdef MODULE_CCCSHARE - char *sharelist_ = getParam(params, "globallist"); - int32_t show_global_list = sharelist_ && sharelist_[0] == '1'; -#else - int32_t show_global_list = 0; -#endif - - struct s_reader *rdr = get_reader_by_label(getParam(params, "label")); - if(show_global_list || cs_strlen(reader_) || (rdr && rdr->typ == R_CCCAM)) - { - - if(show_global_list || (rdr && rdr->typ == R_CCCAM && rdr->enable)) - { - - if(show_global_list) - { - tpl_addVar(vars, TPLADD, "READERNAME", "GLOBAL"); - tpl_addVar(vars, TPLADD, "APIHOST", "GLOBAL"); - tpl_addVar(vars, TPLADD, "APIHOSTPORT", "GLOBAL"); - } - else - { - tpl_addVar(vars, TPLADD, "READERNAME", xml_encode(vars, rdr->label)); - tpl_addVar(vars, TPLADD, "APIHOST", xml_encode(vars, rdr->device)); - tpl_printf(vars, TPLADD, "APIHOSTPORT", "%d", rdr->r_port); - } - - int32_t offset = atoi(getParam(params, "offset")); //should be 0 if parameter is missed on very first call - int32_t cardsize; -#ifdef MODULE_CCCSHARE - if(show_global_list) - { - int32_t i; - LLIST **sharelist = get_and_lock_sharelist(); - LLIST *sharelist2 = ll_create("web-sharelist"); - for(i = 0; i < CAID_KEY; i++) - { - if(sharelist[i]) - { ll_putall(sharelist2, sharelist[i]); } - } - unlock_sharelist(); - struct cc_card **cardarray = get_sorted_card_copy(sharelist2, 0, &cardsize); - ll_destroy(&sharelist2); - print_cards(vars, params, cardarray, cardsize, 1, NULL, offset, apicall); - NULLFREE(cardarray); - } - else -#endif - { - struct s_client *rc = rdr->client; - struct cc_data *rcc = (rc) ? rc->cc : NULL; - if(rcc && rcc->cards) - { - struct cc_card **cardarray = get_sorted_card_copy(rcc->cards, 0, &cardsize); - print_cards(vars, params, cardarray, cardsize, 0, rdr, offset, apicall); - NULLFREE(cardarray); - } - } - - } - else - { -#else - if(cs_strlen(reader_)) - { - { - struct s_reader *rdr; -#endif - tpl_addVar(vars, TPLADD, "LOGHISTORY", "->"); - // normal non-cccam reader - - rdr = get_reader_by_label(reader_); - - if(rdr) - { - struct s_client *cl = rdr->client; - if(rdr->ll_entitlements) - { - - time_t now = time((time_t *)0); - - struct tm start_t, end_t; - LL_ITER itr = ll_iter_create(rdr->ll_entitlements); - S_ENTITLEMENT *item; - - tpl_addVar(vars, TPLAPPEND, "LOGHISTORY", "

New Structure:
"); - char tbuffer[83]; -#ifdef WITH_EMU - char keyBuffer[1024]; -#endif - int jsondelimiter = 0; - while((item = ll_iter_next(&itr))) - { -#ifdef WITH_EMU - if(item->isKey) - { - tpl_addVar(vars, TPLADD, "ENTSTARTDATE", ""); - tpl_addVar(vars, TPLADD, "ENTENDDATE", ""); - cs_hexdump(0, item->key, item->keyLength, keyBuffer, sizeof(keyBuffer)); - tpl_addVar(vars, TPLADD, "ENTEXPIERED", "e_valid"); - tpl_printf(vars, TPLADD, "ENTCAID", "%04X", item->caid); - tpl_printf(vars, TPLADD, "ENTPROVID", "%08X", item->provid); - tpl_addVar(vars, TPLADD, "ENTID", item->name); - tpl_addVar(vars, TPLADD, "ENTCLASS", keyBuffer); - if(item->isData) { tpl_addVar(vars, TPLADD, "ENTTYPE", "data"); } - else { tpl_addVar(vars, TPLADD, "ENTTYPE", "key"); } - tpl_addVar(vars, TPLADD, "ENTRESNAME", ""); - - if((strcmp(getParam(params, "hideexpired"), "1") != 0) || (item->end > now)) - { tpl_addVar(vars, TPLAPPEND, "READERENTENTRY", tpl_getTpl(vars, "ENTITLEMENTITEMBIT")); } - - continue; - } -#endif - - localtime_r(&item->start, &start_t); - localtime_r(&item->end, &end_t); - - if(!apicall) - { strftime(tbuffer, 30, "%Y-%m-%d", &start_t); } - else - { strftime(tbuffer, 30, "%Y-%m-%dT%H:%M:%S%z", &start_t); } - tpl_addVar(vars, TPLADD, "ENTSTARTDATE", tbuffer); - - if(!apicall) - { strftime(tbuffer, 30, "%Y-%m-%d", &end_t); } - else - { strftime(tbuffer, 30, "%Y-%m-%dT%H:%M:%S%z", &end_t); } - tpl_addVar(vars, TPLADD, "ENTENDDATE", tbuffer); - - tpl_addVar(vars, TPLADD, "ENTEXPIERED", item->end > now ? "e_valid" : "e_expired"); - tpl_printf(vars, TPLADD, "ENTCAID", "%04X", item->caid); - tpl_printf(vars, TPLADD, "ENTPROVID", "%06X", item->provid); - tpl_printf(vars, TPLADD, "ENTID", "%08X%08X", (uint32_t)(item->id >> 32), (uint32_t)item->id); - tpl_printf(vars, TPLADD, "ENTCLASS", "%08X", item->class); - tpl_addVar(vars, TPLADD, "ENTTYPE", entitlement_type[item->type]); - - char *entresname; - entresname = xml_encode(vars, get_tiername((uint16_t)(item->id & 0xFFFF), item->caid, tbuffer)); - if(!tbuffer[0]) - { entresname = xml_encode(vars, get_provider(item->provid, item->caid, tbuffer, sizeof(tbuffer))); } - tpl_addVar(vars, TPLADD, "ENTRESNAME", entresname); - - if((strcmp(getParam(params, "hideexpired"), "1") != 0) || (item->end > now)) - { tpl_addVar(vars, TPLAPPEND, "READERENTENTRY", tpl_getTpl(vars, "ENTITLEMENTITEMBIT")); } - - if(apicall==2) - { - tpl_printf(vars, TPLAPPEND, "APIENTITLEMENTLIST","%s%s",jsondelimiter?",":"", tpl_getTpl(vars, "JSONENTITLEMENTBIT")); - jsondelimiter++; - } - } - } - - if(cl && cl->typ) - { tpl_printf(vars, TPLADD, "READERTYPE", "%c", cl->typ); } - else - { tpl_addVar(vars, TPLADD, "READERTYPE", "null"); } - tpl_addVar(vars, TPLADD, "READERNAME", xml_encode(vars, rdr->label)); - - int8_t i, j; - for(i = 0; i < 15; i++) { tpl_printf(vars, TPLAPPEND, "READERROM", "%c", rdr->rom[i]); } - if(rdr->hexserial[0] || rdr->hexserial[1]) { i = 0; } - else { i = 2; } - if(rdr->hexserial[6] || rdr->hexserial[7]) { j = 8; } - else { j = 6; } - for(; i < j; i++) { tpl_printf(vars, TPLAPPEND, "READERSERIAL", "%02X%s", rdr->hexserial[i], i < j - 1 ? " " : ""); } - for(i = 0; i < rdr->nprov; i++) - { - for(j = 0; j < 4; j++) { tpl_printf(vars, TPLAPPEND, "READERPROVIDS", "%02X ", rdr->prid[i][j]); } - tpl_addVar(vars, TPLAPPEND, "READERPROVIDS", i == 0 ? "(sysid)
\n" : "       
\n"); - } - -#ifdef READER_VIDEOGUARD - //CountryCode Vg card - char add_nds_line = 0; - if(rdr->VgCountryC[0]) - { - for(i = 0; i < 3; i++) { tpl_printf(vars, TPLAPPEND, "READERCOUNTRYC", "%c", rdr->VgCountryC[i]); } - add_nds_line = 1; - } - else - { - tpl_addVar(vars, TPLADD, "READERCOUNTRYC", "n/a"); - } - - //regional code for Vg card - if(rdr->VgRegionC[0]) - { - for(i = 0; i < 8; i++) { tpl_printf(vars, TPLAPPEND, "READER_RCODE", "%c", rdr->VgRegionC[i]); } - add_nds_line = 1; - } - else - { - tpl_addVar(vars, TPLADD, "READER_RCODE", "n/a"); - } - - //Pin Vg card - if(rdr->VgPin) - { - tpl_printf(vars, TPLAPPEND, "READERPIN", "%04i", rdr->VgPin); - add_nds_line = 1; - } - else - { - tpl_addVar(vars, TPLADD, "READERPIN", "n/a"); - } - - //Fuse Vg card - if(rdr->VgFuse) - { - tpl_printf(vars, TPLAPPEND, "READERFUSE", "%02X", rdr->VgFuse); - add_nds_line = 1; - } - - if(caid_is_videoguard(rdr->caid)) - { - tpl_printf(vars, TPLAPPEND, "READERPAYLOAD", "%02X %02X %02X %02X %02X %02X", rdr->VgLastPayload[0], - rdr->VgLastPayload[1], rdr->VgLastPayload[2], rdr->VgLastPayload[3], rdr->VgLastPayload[4], rdr->VgLastPayload[5]); - add_nds_line = 1; - } - - //credit on Vg card - if(rdr->VgCredit) - { - tpl_printf(vars, TPLAPPEND, "READERCREDIT", "%i", rdr->VgCredit); - add_nds_line = 1; - } - else - { - tpl_addVar(vars, TPLADD, "READERCREDIT", "n/a"); - } -#endif - - if(rdr->card_valid_to) - { - struct tm vto_t; - char vtobuffer[30]; - localtime_r(&rdr->card_valid_to, &vto_t); - strftime(vtobuffer, 30, "%Y-%m-%d", &vto_t); - tpl_addVar(vars, TPLADD, "READERCARDVALIDTO", vtobuffer); - } - else - { - tpl_addVar(vars, TPLADD, "READERCARDVALIDTO", "n/a"); - } - - if(rdr->irdId[0]) - { - for(i = 0; i < 4; i++) { tpl_printf(vars, TPLAPPEND, "READERIRDID", "%02X ", rdr->irdId[i]); } - } - else - { - tpl_addVar(vars, TPLADD, "READERIRDID", "n/a"); - } - - if(rdr->card_atr_length) - for(i = 0; i < rdr->card_atr_length; i++) { tpl_printf(vars, TPLAPPEND, "READERATR", "%02X ", rdr->card_atr[i]); } - - if(caid_is_seca(rdr->caid) || caid_is_viaccess(rdr->caid)) - { - if(rdr->maturity == 0xF) - { - tpl_printf(vars, TPLAPPEND, "READERMATURITY", "%s ", "no limit"); - } - else - { - tpl_printf(vars, TPLAPPEND, "READERMATURITY", "%d+", rdr->maturity); - } - } - else - { - tpl_printf(vars, TPLAPPEND, "READERMATURITY", "%s ", "n/a"); - } - - if (rdr->csystem) - tpl_addVar(vars, TPLADD, "READERCSYSTEM", rdr->csystem->desc); - -#ifdef READER_VIDEOGUARD - if(add_nds_line) - { - tpl_addVar(vars, TPLADD, "ENTITLEMENTCONTENTNDS", tpl_getTpl(vars, "ENTITLEMENTBITNDS")); - } -#endif - tpl_addVar(vars, TPLADD, "ENTITLEMENTCONTENT", tpl_getTpl(vars, "ENTITLEMENTBIT")); - } - else - { - tpl_addMsg(vars, "Reader does not exist or is not started!"); - } - } - - } - else - { - tpl_addVar(vars, TPLADD, "ENTITLEMENTCONTENT", tpl_getTpl(vars, "ENTITLEMENTGENERICBIT")); - } - - if(!apicall) - { return tpl_getTpl(vars, "ENTITLEMENTS"); } - else - { - if(apicall==1) - { return tpl_getTpl(vars, "APICCCAMCARDLIST"); } - else - { return tpl_getTpl(vars, "JSONENTITLEMENTS"); } - } -} - -#ifdef WEBIF_LIVELOG -static char *send_oscam_logpoll(struct templatevars * vars, struct uriparams * params) -{ - - uint64_t lastid = 0; - -#ifdef WITH_DEBUG - tpl_addVar(vars, TPLADD, "LOG_DEBUGMENU", tpl_getTpl(vars, "LOGDEBUGMENU")); -#endif - tpl_addVar(vars, TPLADD, "LOG_SIZEMENU", tpl_getTpl(vars, "LOGSIZEMENU")); - tpl_addVar(vars, TPLADD, "TITLEADD1", "Move mouse over log-window to stop scroll"); - - if(strcmp(getParam(params, "lastid"), "start") == 0){ - setActiveMenu(vars, MNU_LIVELOG); - return tpl_getTpl(vars, "LOGPAGE"); - } - else - { - lastid = strtoull(getParam(params, "lastid"), NULL, 10); - } - - char *dot = ""; //Delimiter - -#ifdef WITH_DEBUG - char *debuglvl = getParam(params, "debug"); - if(cs_strlen(debuglvl) > 0) { - int32_t dblvl = atoi(debuglvl); - if(cs_dblevel != dblvl) { - if(dblvl >= 0 && dblvl <= 65535) { cs_dblevel = dblvl; } - cs_log("%s debug_level=%d", "all", cs_dblevel); - } - } - tpl_printf(vars, TPLAPPEND, "DATA","%s\"debug\":\"%d\"", dot, cs_dblevel); - dot = ","; - tpl_printf(vars, TPLAPPEND, "DATA","%s\"maxdebug\":\"%d\"",dot, MAX_DEBUG_LEVELS); -#endif - - if(cfg.loghistorylines == 0){ - tpl_printf(vars, TPLAPPEND, "DATA","%s\"logdisabled\":\"1\"",dot); - return tpl_getTpl(vars, "POLL"); - } - - if(log_history) - { - LL_ITER it = ll_iter_create(log_history); - struct s_log_history *hist; - - tpl_printf(vars, TPLAPPEND, "DATA", "%s\"lines\":[", dot); - - dot = ""; - - while((hist = (struct s_log_history*)ll_iter_next(&it))) - { - char p_usr[32]; - size_t pos1 = strcspn(hist->txt, "\t") + 1; - cs_strncpy(p_usr, hist->txt , pos1 > sizeof(p_usr) ? sizeof(p_usr) : pos1); - - char *p_txt = hist->txt + pos1; - - pos1 = strcspn(p_txt, "\n") + 1; - char str_out[pos1]; - cs_strncpy(str_out, p_txt, pos1); - uint64_t id = hist->counter; - - size_t b64_str_in = cs_strlen(xml_encode(vars, str_out)); - size_t b64_str_out = 32 + BASE64_LENGTH(b64_str_in); - char *b64_str_out_buf; - if(!cs_malloc(&b64_str_out_buf, b64_str_out)) - { continue; } - base64_encode(xml_encode(vars, str_out), b64_str_in, b64_str_out_buf, b64_str_out); - - if(id > lastid){ - tpl_printf(vars, TPLAPPEND, "DATA","%s{\"id\":\"%" PRIu64 "\",\"usr\":\"%s\",\"line\":\"%s\"}", - dot, - id, - urlencode(vars, xml_encode(vars, p_usr)), - b64_str_out_buf); - dot = ","; // next in Array with leading delimiter - } - NULLFREE(b64_str_out_buf); - } - } - - tpl_addVar(vars, TPLAPPEND, "DATA", "]"); - return tpl_getTpl(vars, "POLL"); -} -#endif - -static char *send_oscam_status(struct templatevars * vars, struct uriparams * params, int32_t apicall) -{ - const char *usr; - int32_t lsec, isec, chsec, con, cau = 0; - time_t now = time((time_t *)0); - struct tm lt; - int delimiter=0; - - if(!apicall) - { - setActiveMenu(vars, MNU_STATUS); - if (config_enabled(WITH_LB)) - tpl_addVar(vars, TPLADD, "STATUSCOL14HEAD","LB Value/"); - } - if(strcmp(getParam(params, "action"), "kill") == 0) - { - char *cptr = getParam(params, "threadid"); - struct s_client *cl = NULL; - if(cs_strlen(cptr) > 1) - { sscanf(cptr, "%p", (void **)(void *)&cl); } - - if(cl && is_valid_client(cl)) - { - if(is_dvbapi_usr(cl->account->usr)) - { - cs_log("WebIF from %s requests to kill dvbapi client %s -> ignoring!", cs_inet_ntoa(GET_IP()), cl->account->usr); - } - else - { - kill_thread(cl); - cs_log("Client %s killed by WebIF from %s", cl->account->usr, cs_inet_ntoa(GET_IP())); - } - } - } - - if(strcmp(getParam(params, "action"), "resetuserstats") == 0) - { - clear_info_clients_stats(); - } - if(strcmp(getParam(params, "action"), "resetreaderstats") == 0) - { - clear_info_readers_stats(); - } - if(strcmp(getParam(params, "action"), "restart") == 0) - { - struct s_reader *rdr = get_reader_by_label(getParam(params, "label")); - if(rdr) - { - if(rdr->typ != R_GBOX) - { - add_job(rdr->client, ACTION_READER_RESTART, NULL, 0); - } -#ifdef MODULE_GBOX - else - { - restart_gbox_peer(rdr->label, 0, 0); - } -#endif - cs_log("Reader %s restarted by WebIF from %s", rdr->label, cs_inet_ntoa(GET_IP())); - } - } - - char *debuglvl = getParam(params, "debug"); - if(cs_strlen(debuglvl) > 0) - { -#ifndef WITH_DEBUG - cs_log("*** Warning: Debug Support not compiled in ***"); -#else - int32_t dblvl = atoi(debuglvl); - if(dblvl >= 0 && dblvl <= 65535) { cs_dblevel = dblvl; } - cs_log("%s debug_level=%d", "all", cs_dblevel); -#endif - } - - char *hide = getParam(params, "hide"); - if(cs_strlen(hide) > 0) - { - struct s_client *hideidx = NULL; - sscanf(hide, "%p", (void **)(void *)&hideidx); - - if(hideidx && is_valid_client(hideidx)) - { hideidx->wihidden = 1; } - } - - char *hideidle = getParam(params, "hideidle"); - if(cs_strlen(hideidle) > 0) - { - if(atoi(hideidle) == 2) - { - struct s_client *cl; - for(cl = first_client; cl ; cl = cl->next) - { - if(cl->typ == 's' || cl->typ == 'h' || cl->typ == 'm'){ - cl->wihidden = 0; - } - } - } - else if(atoi(hideidle) == 3) - { - struct s_client *cl; - for(cl = first_client; cl ; cl = cl->next) - { - if(cl->typ == 'r'){ - cl->wihidden = 0; - } - } - } - else if(atoi(hideidle) == 4) - { - struct s_client *cl; - for(cl = first_client; cl ; cl = cl->next) - { - if(cl->typ == 'p'){ - cl->wihidden = 0; - } - } - } - else if(atoi(hideidle) == 5) - { - struct s_client *cl; - for(cl = first_client; cl ; cl = cl->next) - { - if(cl->typ == 'c'){ - cl->wihidden = 0; - } - } - } - else - { - int32_t oldval = cfg.http_hide_idle_clients; - config_set("webif", "httphideidleclients", hideidle); - if(oldval != cfg.http_hide_idle_clients) - { - refresh_oscam(REFR_SERVER); - } - } - } - - if(cfg.http_hide_idle_clients > 0) { tpl_addVar(vars, TPLADD, "HIDEIDLECLIENTSSELECTED1", "selected"); } - else { tpl_addVar(vars, TPLADD, "HIDEIDLECLIENTSSELECTED0", "selected"); } - - tpl_addVar(vars, TPLADD, "SRVIDFILE", use_srvid2 ? "oscam.srvid2" : "oscam.srvid"); - - int32_t user_count_all = 0, user_count_shown = 0, user_count_active = 0; - int32_t reader_count_all = 0, reader_count_conn = 0, reader_count_off = 0; - int32_t proxy_count_all = 0, proxy_count_conn = 0, proxy_count_off = 0; - int32_t server_count_all = 0, server_count_shown = 0, server_count_hidden = 0; - int32_t monitor_count_all = 0, monitor_count_shown = 0; - int32_t shown; - - int32_t total_readers = 0; - int32_t active_readers = 0; - int32_t disabled_readers = 0; - int32_t connected_readers = 0; - - struct s_client *cl; - int8_t filtered; - - cs_readlock(__func__, &readerlist_lock); - cs_readlock(__func__, &clientlist_lock); - for(cl = first_client; cl ; cl = cl->next) - { -#ifdef CS_CACHEEX_AIO -#if defined(MODULE_CCCAM) && defined(CS_CACHEEX) - struct cc_data *cc = cl->cc; -#endif -#endif - if(cl->kill) { continue; } -#ifdef CS_CACHEEX - if(get_module(cl)->listenertype != LIS_CSPUDP) - { -#endif - - // Reset template variables - tpl_addVar(vars, TPLADD, "LBLRPSTRVALUE", ""); - tpl_addVar(vars, TPLADD, "CLIENTLBVALUE", ""); - tpl_addVar(vars, TPLADD, "LASTREADER", ""); - tpl_addVar(vars, TPLADD, "CLIENTPROTO", ""); - tpl_addVar(vars, TPLADD, "CLIENTDESCRIPTION", ""); - tpl_addVar(vars, TPLADD, "CLIENTLASTRESPONSETIME", ""); - tpl_addVar(vars, TPLADD, "CLIENTLASTRESPONSETIMEHIST", ""); - tpl_addVar(vars, TPLADD, "UPICMISSING" , ""); - tpl_addVar(vars, TPLADD, "ENTITLEMENTS", ""); - - if(cl->typ == 'c') - { user_count_all++; } - else if(cl->typ == 'p') - { - proxy_count_all++; - if((cl->reader->typ == R_GBOX && cl->reader->card_status != CARD_INSERTED && cl->reader->card_status != NO_CARD) || - (cl->reader->typ != R_GBOX && cl->reader->card_status != CARD_INSERTED)) - { proxy_count_off++; } - } - else if(cl->typ == 'r') - { reader_count_all++; if(cl->reader->card_status != CARD_INSERTED) { reader_count_off++; } } - else if(cl->typ == 's' || cl->typ == 'h') - { server_count_all++; if(cl->wihidden) {server_count_hidden++;} } - else if(cl->typ == 'm') - { monitor_count_all++; } - - shown = 0; - if(cl->wihidden != 1) - { - filtered = !(cfg.http_hide_idle_clients != 1 || cl->typ != 'c' || (now - cl->lastecm) <= cfg.hideclient_to); - if(!filtered && cfg.http_hide_type) - { - char *p = cfg.http_hide_type; - while(*p && !filtered) - { - char type = *p++; -#ifdef CS_CACHEEX - filtered = (type == cl->typ) || (type == 'x' && (cl->typ == 'p' || cl->typ == 'r') && (cl->reader && cl->reader->cacheex.mode)); -#else - filtered = (type == cl->typ); -#endif -#ifdef WITH_EMU - if(type == 'e' && cl->typ == 'r' && cl->reader->typ == R_EMU) filtered = 1; -#endif - } - } - - if(!filtered) - { - if(cl->typ == 'c') - { - user_count_shown++; - if(cfg.http_hide_idle_clients != 1 && cfg.hideclient_to > 0 && (now - cl->lastecm) <= cfg.hideclient_to) - { - user_count_active++; - } - } - else if(cl->typ == 's' || cl->typ == 'h') - { - server_count_shown++; - } - else if(cl->typ == 'm') - { - monitor_count_shown++; - } - else if(cl->typ == 'r') - { - reader_count_conn++; - } - else if(cl->typ == 'p') - { - proxy_count_conn++; - } - - if(cl->typ == 'c' || cl->typ == 'r' || cl->typ == 'p') - { - if(cl->lastecm >= cl->login && cl->lastecm >= cl->logout) { isec = now - cl->lastecm; } - else if(cl->logout >= cl->login) { isec = now - cl->logout; } - else { isec = now - cl->login; } - } - else { isec = now - cl->last; } - - shown = 1; - lsec = now - cl->login; - chsec = now - cl->lastswitch; - usr = username(cl); - - if((cl->typ == 'r') || (cl->typ == 'p')) { usr = cl->reader->label; } - - if(cl->dup) { con = 2; } - else if((cl->tosleep) && (now - cl->lastswitch > cl->tosleep)) { con = 1; } - else { con = 0; } - - // no AU reader == 0 / AU ok == 1 / Last EMM > aulow == -1 - if(cl->typ == 'c' || cl->typ == 'p' || cl->typ == 'r') - { - if((cl->typ == 'c' && ll_count(cl->aureader_list) == 0) || ((cl->typ == 'p' || cl->typ == 'r') && cl->reader->audisabled)) { cau = 0; } - else if((now - cl->lastemm) / 60 > cfg.aulow) { cau = -1; } - else { cau = 1; } - - if(cau == 0) - { - tpl_addVar(vars, TPLADD, "CLIENTCAUHTTP", "OFF"); - } - else - { - if(cau == -1) - { tpl_addVar(vars, TPLADD, "CLIENTCAUHTTP", !apicall?"ON":""); } - else - { tpl_addVar(vars, TPLADD, "CLIENTCAUHTTP", !apicall?"ACTIVE":""); } - tpl_addVar(vars, TPLAPPEND, "CLIENTCAUHTTP", !apicall?"":""); - if(cl->typ == 'c') - { - struct s_reader *rdr; - LL_ITER itr = ll_iter_create(cl->aureader_list); - while((rdr = ll_iter_next(&itr))) - { - if(rdr->audisabled) - { tpl_printf(vars, TPLAPPEND, "CLIENTCAUHTTP", "(%s)
", xml_encode(vars, rdr->label)); } - else - { tpl_printf(vars, TPLAPPEND, "CLIENTCAUHTTP", "%s
", xml_encode(vars, rdr->label)); } - } - } - else { tpl_addVar(vars, TPLAPPEND, "CLIENTCAUHTTP", xml_encode(vars, cl->reader->label)); } - tpl_addVar(vars, TPLAPPEND, "CLIENTCAUHTTP", !apicall?"
":""); - } - } - else - { - cau = 0; - tpl_addVar(vars, TPLADD, "CLIENTCAUHTTP", ""); - } - localtime_r(&cl->login, <); - - if(cl->typ == 'c' || cl->typ == 'm') - { - if(cl->account && cl->account->description) - tpl_printf(vars, TPLADD, "CLIENTDESCRIPTION","%s(%s)",!apicall?" ":"",xml_encode(vars, cl->account->description)); - else - tpl_addVar(vars, TPLADD, "CLIENTDESCRIPTION", ""); - } - else if(cl->typ == 'p' || cl->typ == 'r') - { - if(cl->reader && cl->reader->description) - tpl_printf(vars, TPLADD, "CLIENTDESCRIPTION","%s(%s)",!apicall?" ":"",xml_encode(vars, cl->reader->description)); - else - tpl_addVar(vars, TPLADD, "CLIENTDESCRIPTION", ""); - } - if(!apicall) - { - tpl_addVar(vars, TPLADD, "LBL", xml_encode(vars, usr)); - tpl_printf(vars, TPLADD, "CID", "%p", cl); - if(cl->typ == 'c' || cl->typ == 'm') - { - tpl_addVar(vars, TPLADD, "TARGET", "User"); - tpl_addVar(vars, TPLADD, "CSIDX", tpl_getTpl(vars, "STATUSKBUTTON")); - } - else if(cl->typ == 'p') - { - tpl_addVar(vars, TPLADD, "TARGET", "Proxy"); - tpl_addVar(vars, TPLADD, "LBLENC", urlencode(vars, usr)); - tpl_addVar(vars, TPLADD, "CSIDX", tpl_getTpl(vars, "STATUSRBUTTON")); - } - else if(cl->typ == 'r') - { - tpl_addVar(vars, TPLADD, "TARGET", "Reader"); - tpl_addVar(vars, TPLADD, "LBLENC", urlencode(vars, usr)); - tpl_addVar(vars, TPLADD, "CSIDX", tpl_getTpl(vars, "STATUSRBUTTON")); - } - else if (cl->typ == 'h' || cl->typ == 's') - { - tpl_addVar(vars, TPLADD, "TARGET", "Server"); - tpl_addVar(vars, TPLADD, "CSIDX", ""); - } - tpl_addVar(vars, TPLADD, "HIDEIDX", tpl_getTpl(vars, "STATUSHBUTTON")); - tpl_printf(vars, TPLADD, "CSIDXPLAIN", "id_%p", cl); - } - else - { - tpl_printf(vars, TPLADD, "HIDEIDX", "%p", cl); - tpl_printf(vars, TPLADD, "CSIDX", "id_%p", cl); - } - tpl_printf(vars, TPLADD, "CLIENTTYPE", "%c", cl->typ); - tpl_printf(vars, TPLADD, "CLIENTCNR", "%d", get_threadnum(cl)); - tpl_addVar(vars, TPLADD, "CLIENTUSER", xml_encode(vars, usr)); - - tpl_addVar(vars, TPLADD, "STATUSUSERICON", xml_encode(vars, usr)); - if (cl->typ == 'c' || cl->typ == 'm') - { - tpl_addVar(vars, TPLADD, "USERNAME", xml_encode(vars, usr)); - tpl_addVar(vars, TPLADD, "USERENC", urlencode(vars, usr)); - } - else if (cl->typ == 'p' || cl->typ == 'r') - { - tpl_addVar(vars, TPLADD, "READERNAME", xml_encode(vars, usr)); - tpl_addVar(vars, TPLADD, "READERNAMEENC", urlencode(vars, usr)); - } - - bool picon_shown = false; - const char *status_user_icon_tpl = NULL; - - char picon_name[32]; - if(cfg.http_showpicons) - { - if(picon_exists(xml_encode(vars, usr))) - { - switch (cl->typ) - { - case 'm': // Fall through - case 'c': status_user_icon_tpl = "SUSERICON"; picon_shown = true; break; - case 'p': // Fall through - case 'r': status_user_icon_tpl = "SREADERICON"; picon_shown = true; break; - } - } - else - tpl_printf(vars, TPLADD, "UPICMISSING", "%smissing icon: IC_%s.tpl",!apicall?" ":"",xml_encode(vars, usr)); - } - - if (!picon_shown) - { - switch (cl->typ) - { - case 'm': // Fall through - case 'c': status_user_icon_tpl = "SUSER"; break; - case 'p': // Fall through - case 'r': status_user_icon_tpl = "SREADER"; break; - } - } - - if (status_user_icon_tpl) - tpl_addVar(vars, TPLADD, "STATUSUSERICON", tpl_getTpl(vars, status_user_icon_tpl)); - - tpl_printf(vars, TPLADD, "CLIENTCAU", "%d", cau); - if(!apicall) - { - if(cl->typ == 'c' || cl->typ == 'p' || cl->typ == 'r') - { - if(cl->crypted) { tpl_addVar(vars, TPLADD, "CLIENTCRYPTED", "ON"); } - else { tpl_addVar(vars, TPLADD, "CLIENTCRYPTED", "OFF"); } - } - else { tpl_addVar(vars, TPLADD, "CLIENTCRYPTED", ""); } - } - else { tpl_printf(vars, TPLADD, "CLIENTCRYPTED", "%d", cl->crypted); } - - if(cl->typ == 'r' && cl->reader && !is_network_reader(cl->reader)) - { tpl_addVar(vars, TPLADD, "CLIENTIP", "local"); } - else if(IP_ISSET(cl->ip)) - { tpl_addVar(vars, TPLADD, "CLIENTIP", cs_inet_ntoa(cl->ip)); } - else if((cl->typ == 'p' || cl->typ == 'r') && cl->reader && cl->reader->tcp_connected) - { tpl_addVar(vars, TPLADD, "CLIENTIP", "camd.socket"); } - else if(cl->typ == 'c' && cl->login > cl->logout) - { tpl_addVar(vars, TPLADD, "CLIENTIP", "camd.socket"); } - else - { tpl_addVar(vars, TPLADD, "CLIENTIP", ""); } - - tpl_printf(vars, TPLADD, "CLIENTPORT", "%d", cl->port); - const char *proto = client_get_proto(cl); -#ifdef CS_CACHEEX_AIO - if(cl && - ( (cl->typ == 'c' && cl->account && cl->account->cacheex.feature_bitfield) -#if defined(MODULE_CAMD35) || defined (MODULE_CAMD35_TCP) - || (cl->c35_extmode > 1) -#endif -#ifdef MODULE_CCCAM - || (cc && cc->extended_lg_flagged_cws) -#endif - || (cl->typ == 'p' && cl->reader && cl->reader->cacheex.feature_bitfield)) - ) - { - const char *aio_suffix = " (cx-aio)"; - char *new_proto; - if(cs_malloc(&new_proto, cs_strlen(proto)+cs_strlen(aio_suffix)+1)) { - new_proto[0] = '\0'; - if (!cs_strncat(new_proto, (char *)proto, cs_strlen(proto)+cs_strlen(aio_suffix)+1)) { - cs_log("FIXME!"); - } - if (cs_strncat(new_proto, (char *)aio_suffix, cs_strlen(proto)+cs_strlen(aio_suffix)+1)) { - webif_add_client_proto(vars, cl, (const char*)new_proto, apicall); - } else { - cs_log("FIXME!"); - } - free(new_proto); - } - } else { -#endif - webif_add_client_proto(vars, cl, proto, apicall); -#ifdef CS_CACHEEX_AIO - } -#endif - if(!apicall) - { - if((cl->typ != 'p' && cl->typ != 'r') || cl->reader->card_status == CARD_INSERTED) - { - tpl_printf(vars, TPLADD, "CLIENTLOGINDATE", "%02d.%02d.%02d
%02d:%02d:%02d", lt.tm_mday, lt.tm_mon + 1, lt.tm_year % 100, lt.tm_hour, lt.tm_min, lt.tm_sec); - tpl_addVar(vars, TPLADD, "CLIENTLOGINSECS", sec2timeformat(vars, lsec)); - } - else - { - tpl_addVar(vars, TPLADD, "CLIENTLOGINDATE", ""); - tpl_addVar(vars, TPLADD, "CLIENTLOGINSECS", ""); - } - } - else - { - tpl_printf(vars, TPLADD, "CLIENTLOGINDATEFMT", "%02d.%02d.%02d %02d:%02d:%02d", lt.tm_mday, lt.tm_mon + 1, lt.tm_year % 100, lt.tm_hour, lt.tm_min, lt.tm_sec); - char tbuffer [30]; - strftime(tbuffer, 30, "%Y-%m-%dT%H:%M:%S%z", <); - tpl_addVar(vars, TPLADD, "CLIENTLOGINDATE", tbuffer); - tpl_printf(vars, TPLADD, "CLIENTLOGINSECS", "%d", lsec); - } - - //load historical values from ringbuffer - char *value = get_ecm_historystring(cl); - tpl_addVar(vars, TPLADD, "CLIENTLASTRESPONSETIMEHIST", value); - free_mk_t(value); - - if((isec < cfg.hideclient_to || cfg.hideclient_to == 0 || is_dvbapi_usr(cl->account->usr)) && (cl->typ == 'c' || cl->typ == 'p' || cl->typ == 'r')) - { - if(((cl->typ == 'c')) && (cl->lastreader[0])) - { - tpl_printf(vars, TPLADD, "MSVALUE", PRINTF_LOCAL_D, cl->cwlastresptime); - if(apicall) - { - tpl_addVar(vars, TPLADD, "LASTREADER", (cl->last_caid == NO_CAID_VALUE || isec > cfg.hideclient_to ) ? "" : cl->lastreader); - tpl_addVar(vars, TPLADD, "READERNAMEENC", urlencode(vars, cl->lastreader)); - } - else - { -#ifdef WITH_LB - tpl_addVar(vars, TPLADD, "LBLVALUE", xml_encode(vars, cl->lastreader)); - if(strstr(cl->lastreader, " (cache)")) - { - char lastreader_tmp[cs_strlen(cl->lastreader) - 8]; - tpl_addVar(vars, TPLADD, "CLIENTLBVALUE", tpl_getVar(vars, "LBLRPSTRVALUE")); - cs_strncpy(lastreader_tmp, cl->lastreader, sizeof(lastreader_tmp)); - tpl_addVar(vars, TPLADD, "LBLVALUEENC", urlencode(vars, lastreader_tmp)); - tpl_addVar(vars, TPLADD, "LBLVALUETITLE", xml_encode(vars, lastreader_tmp)); - } - else - { - tpl_addVar(vars, TPLADD, "LBLVALUEENC", urlencode(vars, cl->lastreader)); - tpl_addVar(vars, TPLADD, "LBLVALUETITLE", xml_encode(vars, cl->lastreader)); - } - tpl_addVar(vars, TPLAPPEND, "CLIENTLBVALUE", tpl_getTpl(vars, "CLIENTLBLVALUEBIT")); -#else - tpl_printf(vars, TPLAPPEND, "CLIENTLBVALUE", "%s (%'d ms)", xml_encode(vars, cl->lastreader), cl->cwlastresptime); -#endif - } - if(cl->last_caid == NO_CAID_VALUE || isec > cfg.hideclient_to) tpl_addVar(vars, TPLADD, "CLIENTLBVALUE", ""); - } - if(cl->last_caid != NO_CAID_VALUE || cl->last_srvid != NO_SRVID_VALUE) - { - char channame[CS_SERVICENAME_SIZE]; - const char *lastprovidername; - - get_servicename_or_null(cl, cl->last_srvid, cl->last_provid, cl->last_caid, channame, sizeof(channame)); - if(channame[0] == '\0') - { - cs_strncpy(channame, "unknown", sizeof(channame)); - } - - lastprovidername = get_cl_lastprovidername(cl); - - tpl_printf(vars, TPLADD, "CLIENTCAID", "%04X", cl->last_caid); - tpl_printf(vars, TPLADD, "CLIENTPROVID", "%06X", cl->last_provid); - tpl_printf(vars, TPLADD, "CLIENTSRVID", "%04X", cl->last_srvid); - tpl_printf(vars, TPLADD, "CLIENTSRVPROVIDER", "%s%s%s", (lastprovidername[0] != '\0' && strcmp(lastprovidername, " ")) ? " [" : "", xml_encode(vars, lastprovidername), (lastprovidername[0] != '\0' && strcmp(lastprovidername, " ")) ? "]" : ""); - tpl_addVar(vars, TPLADD, "CLIENTSRVNAME", xml_encode(vars, channame)); - tpl_printf(vars, TPLADD, "CLIENTLASTRESPONSETIME", "%d", cl->cwlastresptime ? cl->cwlastresptime : 1); - tpl_addVar(vars, TPLADD, "CLIENTSRVTYPE", cl->last_srvidptr && cl->last_srvidptr->type ? xml_encode(vars, cl->last_srvidptr->type) : ""); - tpl_addVar(vars, TPLADD, "CLIENTSRVDESCRIPTION", cl->last_srvidptr && cl->last_srvidptr->desc ? xml_encode(vars, cl->last_srvidptr->desc) : ""); - tpl_addVar(vars, TPLADD, "CLIENTTIMEONCHANNEL", sec2timeformat(vars, chsec)); - if(cfg.http_showpicons && cl->last_srvid) - { - char picon_channame[30]; - int8_t picon_ok = 0; - - get_picon_servicename_or_null(cl, cl->last_srvid, cl->last_provid, cl->last_caid, picon_channame, sizeof(picon_channame)); - if(picon_channame[0]) - { - snprintf(picon_name, sizeof(picon_name) / sizeof(char) - 1, "%s", picon_channame); - picon_ok = picon_exists(picon_name); - if(picon_ok) tpl_addVar(vars, TPLADD, "PICONNAME", picon_name); - - if(!picon_ok && picon_servicename_remve_hd(picon_channame, sizeof(picon_channame))) - { - snprintf(picon_name, sizeof(picon_name) / sizeof(char) - 1, "%s", picon_channame); - picon_ok = picon_exists(picon_name); - if(picon_ok) tpl_addVar(vars, TPLADD, "PICONNAME", picon_name); - } - } - if(!picon_ok) - { - snprintf(picon_name, sizeof(picon_name) / sizeof(char) - 1, "%04X_%06X_%04X", cl->last_caid, cl->last_provid, cl->last_srvid); - tpl_addVar(vars, TPLADD, "PICONNAME", picon_name); - picon_ok = picon_exists(picon_name); - } - if(!picon_ok) - { - snprintf(picon_name, sizeof(picon_name) / sizeof(char) - 1, "%04X_%04X", cl->last_caid, cl->last_srvid); - picon_ok = picon_exists(picon_name); - if(picon_ok) tpl_addVar(vars, TPLADD, "PICONNAME", picon_name); - } - if(!picon_ok) - { - snprintf(picon_name, sizeof(picon_name) / sizeof(char) - 1, "0000_%04X", cl->last_srvid); - picon_ok = picon_exists(picon_name); - if(picon_ok) tpl_addVar(vars, TPLADD, "PICONNAME", picon_name); - } - if(picon_ok) - { - tpl_addVar(vars, TPLADDONCE, "CURRENTPICON", tpl_getTpl(vars, "CLIENTCURRENTCHANNELPIC")); - } - else - { - tpl_addVar(vars, TPLADDONCE, "CURRENTPICON", tpl_getTpl(vars, "CLIENTCURRENTCHANNEL")); - tpl_addVar(vars, TPLADD, "PICONNAME", ""); - } - } - else - { - tpl_addVar(vars, TPLADDONCE, "CURRENTPICON", tpl_getTpl(vars, "CLIENTCURRENTCHANNELBIT")); - tpl_addVar(vars, TPLADD, "PICONNAME", "0000_0000"); - } - } - else - { - tpl_addVar(vars, TPLADD, "CLIENTCAID", "0000"); - tpl_addVar(vars, TPLADD, "CLIENTPROVID", "000000"); - tpl_printf(vars, TPLADD, "CLIENTSRVID", "0000"); - } - } - else - { - tpl_addVar(vars, TPLADD, "CLIENTCAID", "0000"); - tpl_addVar(vars, TPLADD, "CLIENTPROVID", "000000"); - tpl_addVar(vars, TPLADD, "CLIENTSRVID", "0000"); - tpl_addVar(vars, TPLADD, "CURRENTPICON", ""); - tpl_addVar(vars, TPLADD, "CLIENTSRVPROVIDER", ""); - tpl_addVar(vars, TPLADD, "CLIENTSRVNAME", ""); - tpl_addVar(vars, TPLADD, "CLIENTSRVTYPE", ""); - tpl_addVar(vars, TPLADD, "CLIENTSRVDESCRIPTION", ""); - tpl_addVar(vars, TPLADD, "CLIENTLBVALUE", ""); - tpl_addVar(vars, TPLADD, "CLIENTTIMEONCHANNEL", ""); - } - - if(!apicall) - { - tpl_addVar(vars, TPLADD, "CLIENTIDLESECS", sec2timeformat(vars, isec)); - - if((cl->typ != 'p' && cl->typ != 'r') || cl->reader->card_status == CARD_INSERTED) - { tpl_addVar(vars, TPLADD, "CLIENTIDLESECSCLASS", "idlesec_normal"); } - else - { tpl_addVar(vars, TPLADD, "CLIENTIDLESECSCLASS", "idlesec_alert"); } - } - else - { - tpl_printf(vars, TPLADD, "CLIENTIDLESECS", "%d", isec); - } - - if(con == 2) { tpl_addVar(vars, TPLADD, "CLIENTCON", "Duplicate"); } - else if(con == 1) { tpl_addVar(vars, TPLADD, "CLIENTCON", "Sleep"); } - else - { - struct s_reader *rdr = cl->reader; - char *txt = "OK"; - if(!rdr && (cl->typ == 'r' || cl->typ == 'p')) { txt = "UNKNOWN"; } - - else if(cl->typ == 'r' || cl->typ == 'p') //reader or proxy - { -#ifdef WITH_LB - if(rdr->lbvalue) - { - tpl_printf(vars, TPLADD, "LBLRPSTRVALUE", "%d", rdr->lbvalue); - } - else - { - tpl_addVar(vars, TPLADD, "LBLRPSTRVALUE", "no data"); - } - tpl_addVar(vars, TPLADD, "LBLRPVALUE", rdr->label); - tpl_addVar(vars, TPLADD, "LBLRPVALUEENC", urlencode(vars, rdr->label)); - tpl_addVar(vars, TPLADD, "CLIENTLBVALUE", tpl_getTpl(vars, "CLIENTLBLVALUERP")); -#else - tpl_addVar(vars, TPLADD, "CLIENTLBVALUE", tpl_getVar(vars, "LBLRPSTRVALUE")); -#endif - switch(rdr->card_status) - { - case NO_CARD: - if(rdr->typ == R_GBOX) - { txt = "ONL"; } - else - { txt = "OFF"; } - break; - case UNKNOWN: - txt = "UNKNOWN"; - break; - case READER_DEVICE_ERROR: - txt = "READER DEVICE ERROR"; - break; - case CARD_NEED_INIT: - if(rdr->typ == R_GBOX) - { txt = "OFFLINE"; } -#ifdef CS_CACHEEX - else if (cl->reader->cacheex.mode > 0) - { txt = "CCcam CacheEX"; } -#endif - else - { txt = "NEEDINIT"; } - break; - case CARD_INSERTED: - if(cl->typ == 'p') - { - if(rdr->typ == R_GBOX) - { txt = "ONL"; } - else - { txt = "CONNECTED"; } - } - else - { txt = "CARDOK"; } - break; - case CARD_FAILURE: - txt = "ERROR"; - break; - default: - txt = "UNDEF"; - } -#ifdef MODULE_GBOX - if(rdr->typ == R_GBOX) - { - struct gbox_peer *peer = cl->gbox; - char gbx_txt[45]; - memset(gbx_txt, 0, sizeof(gbx_txt)); - if(!strcmp(txt, "OFFLINE")) - { - snprintf(gbx_txt, sizeof(gbx_txt), "%s | ID: %04X", txt, peer->gbox.id); - } - else - { - snprintf(gbx_txt, sizeof(gbx_txt), "%s | crd: %d | ID: %04X", txt, gbox_count_peer_cards(peer->gbox.id), peer->gbox.id); - } - txt = gbx_txt; - } -#endif - } - - tpl_addVar(vars, TPLADD, "CLIENTCON", txt); - - if(rdr && (cl->typ == 'r')) //reader - { - if(rdr->ll_entitlements) - { - LL_ITER itr = ll_iter_create(rdr->ll_entitlements); - S_ENTITLEMENT *ent; - uint16_t total_ent = 0; - uint16_t active_ent = 0; - struct tm end_t; - tpl_addVar(vars, TPLADD, "TMPSPAN", ""); - while((ent = ll_iter_next(&itr))) - { - total_ent++; - if((ent->end > now) && (ent->type != 7)) - { - if(active_ent) {tpl_addVar(vars, TPLAPPEND, "TMPSPAN", "

");} - active_ent++; - localtime_r(&ent->end, &end_t); - tpl_printf(vars, TPLAPPEND, "TMPSPAN", "%04X@%06X
exp:%04d/%02d/%02d", - ent->caid, ent->provid, - end_t.tm_year + 1900, end_t.tm_mon + 1, end_t.tm_mday); - tpl_printf(vars, TPLAPPEND, "ENTITLEMENTS", "%s{\"caid\":\"%04X\",\"provid\":\"%06X\",\"exp\":\"%04d/%02d/%02d\"}", - active_ent > 1 ? ",": "", - ent->caid, ent->provid, - end_t.tm_year + 1900, end_t.tm_mon + 1, end_t.tm_mday); - } - } - tpl_printf(vars, TPLADD, "TOTENTITLEMENTS", "%d", total_ent); - if(((total_ent) && (active_ent == 0)) || (total_ent == 0)) - { - tpl_addVar(vars, TPLAPPEND, "TMPSPAN", "No active entitlements found"); - } - tpl_addVar(vars, TPLAPPEND, "TMPSPAN", "
"); - if(active_ent) - { - tpl_printf(vars, TPLADD, "TMP", "(%d entitlement%s)", active_ent, (active_ent != 1) ? "s" : ""); - } - else - { - tpl_addVar(vars, TPLADD, "TMP", "(no entitlements)"); - } - tpl_addVar(vars, TPLADD, "ENTLABEL", urlencode(vars, cl->reader->label)); - tpl_addVar(vars, TPLADD, "ENTVALUE", active_ent > 0 ? "" : "1"); - if (!apicall) tpl_addVar(vars, TPLAPPEND, "CLIENTCON", tpl_getTpl(vars, "FOUNDENTITLEMENTS")); - } - else - { - tpl_addVar(vars, TPLADD, "ENTLABEL", urlencode(vars, cl->reader->label)); - if (!apicall) tpl_addVar(vars, TPLAPPEND, "CLIENTCON", tpl_getTpl(vars, "NOENTITLEMENTS")); - } - } -#ifdef MODULE_CCCAM - if(!apicall || apicall == 2) - { - if(rdr && (cl->typ == 'r' || cl->typ == 'p') && strncmp(proto, "cccam", 5) == 0 && rdr->tcp_connected && rdr->card_status != CARD_FAILURE) - { - struct cc_data *rcc = cl->cc; - if(rcc) - { - LLIST *cards = rcc->cards; - if(cards) - { - int32_t cnt = ll_count(cards); - int32_t locals = rcc->num_hop1; - if(!apicall) - { - tpl_printf(vars, TPLADD, "TMP", "(%d of %d card%s)", locals, cnt, (cnt > 1) ? "s" : ""); - tpl_printf(vars, TPLADD, "CCCOUNT", "%d", cnt); - tpl_printf(vars, TPLADD, "CCCHOP1", "%d", rcc->num_hop1); - tpl_printf(vars, TPLADD, "CCCHOP2", "%d", rcc->num_hop2); - tpl_printf(vars, TPLADD, "CCCHOPX", "%d", rcc->num_hopx); - tpl_printf(vars, TPLADD, "CCCCURR", "%d", cl->reader->currenthops); - tpl_printf(vars, TPLADD, "CCCRES0", "%d", rcc->num_reshare0); - tpl_printf(vars, TPLADD, "CCCRES1", "%d", rcc->num_reshare1); - tpl_printf(vars, TPLADD, "CCCRES2", "%d", rcc->num_reshare2); - tpl_printf(vars, TPLADD, "CCCRESX", "%d", rcc->num_resharex); - tpl_addVar(vars, TPLADD, "TMPSPAN", tpl_getTpl(vars, "CCENTITLEMENTS")); - tpl_addVar(vars, TPLADD, "CCCLABEL", urlencode(vars, cl->reader->label)); - tpl_addVar(vars, TPLADD, "CCCRESHARE", rcc->num_reshare0 > 0 ? "1" : ""); - tpl_addVar(vars, TPLADD, "CCCTMP", tpl_getVar(vars, "TMP")); - tpl_addVar(vars, TPLADD, "CCCTMPSPAN", tpl_getVar(vars, "TMPSPAN")); - tpl_addVar(vars, TPLAPPEND, "CLIENTCON", tpl_getTpl(vars, "CCENTITLETOOLTIP")); - } - if (apicall == 2) - { - tpl_addVar(vars, TPLADD, "READERNAMEENC", urlencode(vars, cl->reader->label)); - tpl_printf(vars, TPLADD, "ENTITLEMENTS", "{\"locals\":\"%d\",\"cccount\":\"%d\",\"ccchop1\":\"%d\",\"ccchop2\":\"%d\",\"ccchopx\":\"%d\",\"ccccurr\":\"%d\",\"cccres0\":\"%d\",\"cccres1\":\"%d\",\"cccres2\":\"%d\",\"cccresx\":\"%d\",\"cccreshare\":\"%s\"}", - locals, cnt, rcc->num_hop1, rcc->num_hop2, rcc->num_hopx, cl->reader->currenthops, - rcc->num_reshare0, rcc->num_reshare1, rcc->num_reshare2, rcc->num_resharex, - rcc->num_reshare0 > 0 ? "1" : ""); - } - cs_log_dbg(D_TRACE, "Reader %s has total %d local%s hop1 %d hopx %d from total of %d card%s", cl->reader->label, locals, (locals > 1) ? "s" : "", rcc->num_hop2, rcc->num_hopx, cnt, (cnt > 1) ? "s" : ""); - } - } - } - } -#endif - } - } - } - if(!apicall) - { - // select right suborder - if(cl->typ == 'c') - { - if(shown) { tpl_addVar(vars, TPLAPPEND, "CLIENTSTATUS", tpl_getTpl(vars, "CLIENTSTATUSBIT")); } - if(cfg.http_hide_idle_clients != 1 && cfg.hideclient_to > 0) - { - tpl_printf(vars, TPLADD, "UCAC", "%d", user_count_active); - tpl_printf(vars, TPLADD, "CFGH", "%d", cfg.hideclient_to); - tpl_addVar(vars, TPLADD, "CHEADADD", tpl_getTpl(vars, "CLIENTHEADLINEADD")); - } - - tpl_printf(vars, TPLADD, "UCS", "%d", user_count_shown); - tpl_printf(vars, TPLADD, "UCA", "%d", user_count_all); - tpl_addVar(vars, TPLADD, "HIDEIDLE", "5"); - tpl_addVar(vars, TPLADD, "SHOWHIDDEN", "User"); - tpl_addVar(vars, TPLADD, "XHEAD", tpl_getTpl(vars, "CLIENTHEADLINE")); - tpl_addVar(vars, TPLADD, "CLIENTOPTIONADD", tpl_getTpl(vars, "CLIENTHEADLINEBIT")); - tpl_addVar(vars, TPLADD, "CLIENTHEADLINE", tpl_getTpl(vars, "STATUSHEADLINE")); - tpl_addVar(vars, TPLADD, "CLIENTOPTIONADD", ""); - } - else if(cl->typ == 'r') - { - if(shown) - { - tpl_addVar(vars, TPLAPPEND, "READERSTATUS", tpl_getTpl(vars, "CLIENTSTATUSBIT")); - } - - tpl_printf(vars, TPLADD, "RCC", "%d", reader_count_conn); - tpl_printf(vars, TPLADD, "RCA", "%d", reader_count_all); - - if(reader_count_off) - { - tpl_printf(vars, TPLADD, "RCO", "%d", reader_count_all-reader_count_off); - tpl_addVar(vars, TPLADD, "RHEADADD", tpl_getTpl(vars, "CLIENTRHEADLINEADD")); - } - - tpl_addVar(vars, TPLADD, "HIDEIDLE", "3"); - tpl_addVar(vars, TPLADD, "SHOWHIDDEN", "Reader"); - tpl_addVar(vars, TPLADD, "XHEAD", tpl_getTpl(vars, "CLIENTRHEADLINE")); - tpl_addVar(vars, TPLADD, "READERHEADLINE", tpl_getTpl(vars, "STATUSHEADLINE")); - } - else if(cl->typ == 'p') - { - if(shown) - { - tpl_addVar(vars, TPLAPPEND, "PROXYSTATUS", tpl_getTpl(vars, "CLIENTSTATUSBIT")); - } - - tpl_printf(vars, TPLADD, "PCC", "%d", proxy_count_conn); - tpl_printf(vars, TPLADD, "PCA", "%d", proxy_count_all); - - if(proxy_count_off) - { - tpl_printf(vars, TPLADD, "PCO", "%d", proxy_count_all-proxy_count_off); - tpl_addVar(vars, TPLADD, "PHEADADD", tpl_getTpl(vars, "CLIENTPHEADLINEADD")); - } - - tpl_addVar(vars, TPLADD, "HIDEIDLE", "4"); - tpl_addVar(vars, TPLADD, "SHOWHIDDEN", "Proxy"); - tpl_addVar(vars, TPLADD, "XHEAD", tpl_getTpl(vars, "CLIENTPHEADLINE")); - tpl_addVar(vars, TPLADD, "PROXYHEADLINE", tpl_getTpl(vars, "STATUSHEADLINE")); - } - else if(cl->typ == 'm' || cl->typ == 's' || cl->typ == 'h') - { - if(shown) - { - tpl_addVar(vars, TPLAPPEND, "SERVERSTATUS", tpl_getTpl(vars, "CLIENTSTATUSBIT")); - } - - tpl_addVar(vars, TPLADD, "HIDEIDLE", "2"); - tpl_addVar(vars, TPLADD, "SHOWHIDDEN", "Server"); - - if(cl->typ == 's' || cl->typ == 'h') - { - tpl_printf(vars, TPLADD, "SCS", "%d", server_count_shown); - tpl_printf(vars, TPLADD, "SCA", "%d", server_count_all); - tpl_addVar(vars, TPLADD, "XHEAD", tpl_getTpl(vars, "CLIENTSHEADLINE")); - - if(shown || cl->wihidden) - { - tpl_addVar(vars, TPLADD, "SERVERHEADLINE", tpl_getTpl(vars, "STATUSHEADLINE")); - } - } - else - { - tpl_addVar(vars, TPLADD, "SHOWHIDDENADD", " & Monitors"); - tpl_printf(vars, TPLADD, "MCS", "%d", monitor_count_shown); - tpl_printf(vars, TPLADD, "MCA", "%d", monitor_count_all); - tpl_addVar(vars, TPLADD, "MHEADADD", tpl_getTpl(vars, "CLIENTMHEADLINE")); - tpl_addVar(vars, TPLADD, "XHEAD", tpl_getTpl(vars, "CLIENTSHEADLINE")); - tpl_addVar(vars, TPLADD, "SERVERHEADLINE", tpl_getTpl(vars, "STATUSHEADLINE")); - tpl_addVar(vars, TPLADD, "SHOWHIDDENADD", ""); - } - } - } - else - { - if(shown) - { - if(apicall == 1) - { - tpl_addVar(vars, TPLAPPEND, "APISTATUSBITS", tpl_getTpl(vars, "APISTATUSBIT")); - } - - if(apicall == 2) - { - tpl_addVar(vars, TPLADD, "JSONARRAYDELIMITER", delimiter?",":""); - tpl_addVar(vars, TPLAPPEND, "JSONSTATUSBITS", tpl_getTpl(vars, "JSONSTATUSBIT")); - delimiter++; - } - } - } - -#ifdef CS_CACHEEX - } -#endif - - } - - LL_ITER itr = ll_iter_create(configured_readers); - struct s_reader *rdrr; - while((rdrr = ll_iter_next(&itr))) - { - if(rdrr->label[0] && rdrr->typ) - { - total_readers += 1; - - if(rdrr->enable) { active_readers += 1; } - else { disabled_readers += 1; } - - if(rdrr->tcp_connected) { connected_readers += 1; } - } - } - - cs_readunlock(__func__, &clientlist_lock); - cs_readunlock(__func__, &readerlist_lock); - - if(cfg.http_status_log || (apicall == 1 && strcmp(getParam(params, "appendlog"), "1") == 0)) - { - if(cfg.loghistorylines && log_history) - { - LL_ITER it = ll_iter_create(log_history); - struct s_log_history *hist; - - while((hist = (struct s_log_history*)ll_iter_next(&it))) - { - char p_usr[32]; - size_t pos1 = strcspn(hist->txt, "\t") + 1; - cs_strncpy(p_usr, hist->txt , pos1 > sizeof(p_usr) ? sizeof(p_usr) : pos1); - - char *p_txt = hist->txt + pos1; - - if(!apicall) - { - if(p_txt[0]) tpl_printf(vars, TPLAPPEND, "LOGHISTORY","\t\t%s\t\t
\n", xml_encode(vars, p_usr), xml_encode(vars, p_txt)); - } - else - { - tpl_addVar(vars, TPLAPPEND, "LOGHISTORY", p_txt); - } - } - } - else - { - tpl_addVar(vars, TPLADD, "LOGHISTORY", "loghistorylines is set to 0 in your configuration"); - } - } - -#ifdef CS_CACHEEX - char *getting = "\"Getting\""; - char *pushing = "\"Pushing\""; - - float cachesum = first_client ? first_client->cwcacheexgot : 1; - if(cachesum < 1) - { - cachesum = 1; - } - tpl_printf(vars, TPLADD, "TOTAL_CACHEXPUSH", "%d", first_client ? first_client->cwcacheexpush : 0); - tpl_addVar(vars, TPLADD, "TOTAL_CACHEXPUSH_IMG", pushing); - tpl_printf(vars, TPLADD, "TOTAL_CACHEXGOT", "%d", first_client ? first_client->cwcacheexgot : 0); - tpl_addVar(vars, TPLADD, "TOTAL_CACHEXGOT_IMG", getting); - tpl_printf(vars, TPLADD, "TOTAL_CACHEXHIT", "%d", first_client ? first_client->cwcacheexhit : 0); - tpl_printf(vars, TPLADD, "TOTAL_CACHESIZE", "%d", cache_size()); -#ifdef CS_CACHEEX_AIO - tpl_printf(vars, TPLADD, "TOTAL_CACHESIZE_LG", "%d", cache_size_lg()); -#endif - tpl_printf(vars, TPLADD, "REL_CACHEXHIT", "%.2f", (first_client ? first_client->cwcacheexhit : 0) * 100 / cachesum); - tpl_addVar(vars, TPLADD, "CACHEEXSTATS", tpl_getTpl(vars, "STATUSCACHEX")); -#endif - //User info - struct s_auth *account; - int32_t total_users = 0; - int32_t disabled_users = 0; - int32_t expired_users = 0; - int32_t expired_or_disabled_users = 0; - int32_t connected_users = 0; - int32_t online_users = 0; - - for(account = cfg.account; (account); account = account->next) - { - total_users++; - if(account->expirationdate && account->expirationdate < now) - { - expired_users++; - } - if(account->disabled != 0) - { - disabled_users++; - } - if((account->expirationdate && account->expirationdate < now)||account->disabled != 0) - { - expired_or_disabled_users++; - } - int32_t latestactivity = 0; - struct s_client *latestclient = NULL; - for(cl = first_client->next; cl ; cl = cl->next) - { - if(cl->account && !strcmp(cl->account->usr, account->usr)) - { - if(cl->lastecm > latestactivity || cl->login > latestactivity) - { - if(cl->lastecm > cl->login) { latestactivity = cl->lastecm; } - else { latestactivity = cl->login; } - latestclient = cl; - } - } - } - - if(latestclient != NULL) - { - connected_users++; - - if(latestactivity > 0) - { - if((now - latestactivity) < cfg.hideclient_to) - { - if(latestclient->cwfound + latestclient->cwnot + latestclient->cwcache > 0) - { - online_users++; - } - } - } - } - } - tpl_printf(vars, TPLADD, "TOTAL_USERS", "%d", total_users); - tpl_printf(vars, TPLADD, "TOTAL_ACTIVE", "%d", total_users - expired_or_disabled_users); - tpl_printf(vars, TPLADD, "TOTAL_EXPIRED", "%d", expired_users); - tpl_printf(vars, TPLADD, "TOTAL_DISABLED", "%d", disabled_users); - tpl_printf(vars, TPLADD, "TOTAL_ONLINE", "%d", online_users); - tpl_printf(vars, TPLADD, "TOTAL_CONNECTED", "%d", connected_users); - - tpl_printf(vars, TPLADD, "TOTAL_READERS", "%d", total_readers); - tpl_printf(vars, TPLADD, "TOTAL_DISABLED_READERS", "%d", disabled_readers); - tpl_printf(vars, TPLADD, "TOTAL_ACTIVE_READERS", "%d", active_readers); - tpl_printf(vars, TPLADD, "TOTAL_CONNECTED_READERS", "%d", connected_readers); - - //CM info - set_ecm_info(vars); - - //copy struct to p_stat_old for cpu_usage calculation - p_stat_old = p_stat_cur; - -/* - * check_available Bit mapping - * mem 0 total, 1 used & free, 2 buff, cached & free incl. buff, 3 share - * swap 4 total, 5 used & free, - * proc 6 count - * cpu 7 load - * oscam 8 vsize & rssize, 9 cpu user, 10 cpu sys, 11 cpu sum, 12 cpu refreshtime - * unused 13 - 15 -*/ - //Memory-CPU Info for linux based systems -#if defined(__linux__) - //get actual stats - if(!get_stats_linux(getpid(),&p_stat_cur)){ - if(p_stat_old.cpu_total_time != 0){ - calc_cpu_usage_pct(&p_stat_cur, &p_stat_old); - } - } - else{ - //something went wrong, so fill with "N/A" - p_stat_cur.check_available = 65535; - } -#else // if not linux, fill with "N/A" but probably in future gets filled also for other platforms - p_stat_cur.check_available = 65535; -#endif - set_status_info(vars, p_stat_cur); - - if(cfg.http_showmeminfo || cfg.http_showuserinfo || cfg.http_showreaderinfo || cfg.http_showloadinfo || cfg.http_showecminfo || (cfg.http_showcacheexinfo && config_enabled(CS_CACHEEX)) || (cfg.http_showcacheexinfo && config_enabled(CS_CACHEEX_AIO))){ - tpl_addVar(vars, TPLADD, "DISPLAYINFO", "visible"); - } - else{ - tpl_addVar(vars, TPLADD, "DISPLAYINFO", "hidden"); - } - - tpl_addVar(vars, TPLADD, "DISPLAYSYSINFO", cfg.http_showmeminfo ? "visible" : "hidden"); - tpl_addVar(vars, TPLADD, "DISPLAYUSERINFO", cfg.http_showuserinfo ? "visible" : "hidden"); - tpl_addVar(vars, TPLADD, "DISPLAYREADERINFO", cfg.http_showreaderinfo ? "visible" : "hidden"); - tpl_addVar(vars, TPLADD, "DISPLAYLOADINFO", cfg.http_showloadinfo ?"visible" : "hidden"); - tpl_addVar(vars, TPLADD, "DISPLAYECMINFO", cfg.http_showecminfo ? "visible" : "hidden"); - tpl_addVar(vars, TPLADD, "DISPLAYECMINFO_READERS", cfg.http_showecminfo ? "visible" : "hidden"); - - if(cfg.http_showcacheexinfo == 1 && config_enabled(CS_CACHEEX)) - { - if (config_enabled(CS_CACHEEX_AIO)) - { - tpl_addVar(vars, TPLADD, "DISPLAYCACHEEXINFO", "hidden"); - tpl_addVar(vars, TPLADD, "DISPLAYCACHEEXAIOINFO", "visible"); - } - else - { - tpl_addVar(vars, TPLADD, "DISPLAYCACHEEXINFO", "visible"); - tpl_addVar(vars, TPLADD, "DISPLAYCACHEEXAIOINFO", "hidden"); - } - } - else{ - tpl_addVar(vars, TPLADD, "DISPLAYCACHEEXINFO", "hidden"); - tpl_addVar(vars, TPLADD, "DISPLAYCACHEEXAIOINFO", "hidden"); - } - -#ifdef WITH_DEBUG - if(cfg.http_status_log) - { - // Debuglevel Selector - int32_t i, lvl; - for(i = 0; i < MAX_DEBUG_LEVELS; i++) - { - lvl = 1 << i; - tpl_printf(vars, TPLADD, "TMPC", "DCLASS%d", lvl); - tpl_printf(vars, TPLADD, "TMPV", "DEBUGVAL%d", lvl); - if(cs_dblevel & lvl) - { - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMPC"), "debugls"); - tpl_printf(vars, TPLADD, tpl_getVar(vars, "TMPV"), "%d", cs_dblevel - lvl); - } - else - { - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMPC"), "debugl"); - tpl_printf(vars, TPLADD, tpl_getVar(vars, "TMPV"), "%d", cs_dblevel + lvl); - } - } - - if(cs_dblevel == D_ALL_DUMP) - { tpl_addVar(vars, TPLADD, "DCLASS65535", "debugls"); } - else - { tpl_addVar(vars, TPLADD, "DCLASS65535", "debugl"); } - - tpl_addVar(vars, TPLADD, "NEXTPAGE", "status.html"); - tpl_addVar(vars, TPLADD, "DCLASS", "debugl"); //default - tpl_printf(vars, TPLADD, "ACTDEBUG", "%d", cs_dblevel); -#ifdef CS_CACHEEX_AIO - tpl_addVar(vars, TPLADD, "SDEBUG", tpl_getTpl(vars, "DEBUGSELECTAIO")); -#else - tpl_addVar(vars, TPLADD, "SDEBUG", tpl_getTpl(vars, "DEBUGSELECT")); -#endif - } -#endif - - if(cfg.http_status_log) - tpl_addVar(vars, TPLADDONCE, "LOG_HISTORY", tpl_getTpl(vars, "LOGHISTORYBIT")); - - if(apicall) - { - if(apicall == 1) - { return tpl_getTpl(vars, "APISTATUS"); } - if(apicall == 2) - { - tpl_printf(vars, TPLADD, "UCS", "%d", user_count_shown); - tpl_printf(vars, TPLADD, "UCA", "%d", user_count_all); - if(cfg.http_hide_idle_clients != 1 && cfg.hideclient_to > 0){ - tpl_printf(vars, TPLADD, "UCAC", "%d", user_count_active); - } - tpl_printf(vars, TPLADD, "CFGH", "%d", cfg.hideclient_to); - tpl_printf(vars, TPLADD, "MCS", "%d", monitor_count_shown); - tpl_printf(vars, TPLADD, "MCA", "%d", monitor_count_all); - tpl_printf(vars, TPLADD, "SCS", "%d", server_count_shown); - tpl_printf(vars, TPLADD, "SCH", "%d", server_count_hidden); - tpl_printf(vars, TPLADD, "SCA", "%d", server_count_all); - tpl_printf(vars, TPLADD, "RCC", "%d", reader_count_conn); - tpl_printf(vars, TPLADD, "RCO", "%d", reader_count_off); - tpl_printf(vars, TPLADD, "RCA", "%d", reader_count_all); - tpl_printf(vars, TPLADD, "PCC", "%d", proxy_count_conn); - tpl_printf(vars, TPLADD, "PCO", "%d", proxy_count_off); - tpl_printf(vars, TPLADD, "PCA", "%d", proxy_count_all); - tpl_printf(vars, TPLADD, "PICONENABLED", "%d", cfg.http_showpicons?1:0); - tpl_printf(vars, TPLADD, "SRVIDFILE", "%s", use_srvid2 ? "oscam.srvid2" : "oscam.srvid"); - return tpl_getTpl(vars, "JSONSTATUS"); - } - } - - return tpl_getTpl(vars, "STATUS"); -} - -static char *send_oscam_services_edit(struct templatevars * vars, struct uriparams * params) -{ - struct s_sidtab *sidtab, *ptr; - char label[sizeof(cfg.sidtab->label)]; - int32_t i; - - setActiveMenu(vars, MNU_SERVICES); - - cs_strncpy(label, strtolower(getParam(params, "service")), sizeof(label)); - ++cfg_sidtab_generation; - for(sidtab = cfg.sidtab; sidtab != NULL && strcmp(label, sidtab->label) != 0; sidtab = sidtab->next) { ; } - - if(sidtab == NULL) - { - i = 1; - while(cs_strlen(label) < 1) - { - snprintf(label, sizeof(label) / sizeof(char) - 1, "newservice%d", i); - for(sidtab = cfg.sidtab; sidtab != NULL && strcmp(label, sidtab->label) != 0; sidtab = sidtab->next) { ; } - if(sidtab != NULL) { label[0] = '\0'; } - ++i; - } - if(!cs_malloc(&sidtab, sizeof(struct s_sidtab))) { return "0"; } - - if(cfg.sidtab == NULL) { cfg.sidtab = sidtab; } - else - { - for(ptr = cfg.sidtab; ptr != NULL && ptr->next != NULL; ptr = ptr->next) { ; } - ptr->next = sidtab; - } - cs_strncpy((char *)sidtab->label, label, sizeof(sidtab->label)); - ++cfg_sidtab_generation; - tpl_addMsg(vars, "New service has been added"); - // Adding is uncritical as the new service is appended to sidtabs.ok/sidtabs.no and accounts/clients/readers have zeros there - if(write_services() != 0) { tpl_addMsg(vars, "Writing services to disk failed!"); } - } - - if(strcmp(getParam(params, "action"), "Save") == 0) - { - for(i = 0; i < (*params).paramcount; i++) - { - if((strcmp((*params).params[i], "action")) && (strcmp((*params).params[i], "service"))) - { - chk_sidtab((*params).params[i], (*params).values[i], sidtab); - } - } - ++cfg_sidtab_generation; - tpl_addMsg(vars, "Services updated"); - // We don't need any refresh here as accounts/clients/readers sidtabs.ok/sidtabs.no are unaffected! - if(write_services() != 0) { tpl_addMsg(vars, "Write Config failed!"); } - - for(sidtab = cfg.sidtab; sidtab != NULL && strcmp(label, sidtab->label) != 0; sidtab = sidtab->next) { ; } - } - - if(sidtab) - { - tpl_addVar(vars, TPLADD, "LABEL", xml_encode(vars, sidtab->label)); - tpl_addVar(vars, TPLADD, "LABELENC", urlencode(vars, sidtab->label)); -#ifdef CS_CACHEEX_AIO - tpl_addVar(vars, TPLADD, "DCRCCHECKED", (sidtab->disablecrccws_only_for_exception == 1) ? "checked" : "" ); - tpl_addVar(vars, TPLADD, "NWCHECKED", (sidtab->no_wait_time == 1) ? "checked" : "" ); - tpl_addVar(vars, TPLADD, "LGOECHECKED", (sidtab->lg_only_exception == 1) ? "checked" : "" ); -#endif - for(i = 0; i < sidtab->num_caid; i++) - { - if(i == 0) { tpl_printf(vars, TPLADD, "CAIDS", "%04X", sidtab->caid[i]); } - else { tpl_printf(vars, TPLAPPEND, "CAIDS", ",%04X", sidtab->caid[i]); } - } - for(i = 0; i < sidtab->num_provid; i++) - { - if(i == 0) { tpl_printf(vars, TPLADD, "PROVIDS", "%06X", sidtab->provid[i]); } - else { tpl_printf(vars, TPLAPPEND, "PROVIDS", ",%06X", sidtab->provid[i]); } - } - for(i = 0; i < sidtab->num_srvid; i++) - { - if(i == 0) { tpl_printf(vars, TPLADD, "SRVIDS", "%04X", sidtab->srvid[i]); } - else { tpl_printf(vars, TPLAPPEND, "SRVIDS", ",%04X", sidtab->srvid[i]); } - } - } -#ifdef CS_CACHEEX_AIO - return tpl_getTpl(vars, "SERVICEEDITAIO"); -#else - return tpl_getTpl(vars, "SERVICEEDIT"); -#endif -} - -static void delete_from_SIDTABBITS(SIDTABBITS * orgsidtab, int32_t position, int32_t sidtablength) -{ - if(*orgsidtab) - { - int32_t i; - SIDTABBITS newsidtab = 0; - for(i = 0; i < position; ++i) - { - if(*orgsidtab & ((SIDTABBITS)1 << i)) - { newsidtab |= ((SIDTABBITS)1 << i); } - } - for(; i < sidtablength; ++i) - { - if(*orgsidtab & ((SIDTABBITS)1 << (i + 1))) - { newsidtab |= ((SIDTABBITS)1 << i); } - } - *orgsidtab = newsidtab; - } -} - -static char *send_oscam_services(struct templatevars * vars, struct uriparams * params) -{ - struct s_sidtab *sidtab; - char *service = getParam(params, "service"); - char channame[CS_SERVICENAME_SIZE]; - int32_t i, counter = 0; - - setActiveMenu(vars, MNU_SERVICES); - - if(strcmp(getParam(params, "action"), "delete") == 0) - { - if(cfg.http_readonly) - { - tpl_addMsg(vars, "Sorry, Webif is in readonly mode. No deletion will be made!"); - } - else - { - struct s_sidtab *sidtab_prev = NULL; - int32_t sidtablength = -1; - int32_t position = 0; - - // Calculate sidtablength before deletion so that updating sidtabs is faster - for(sidtab = cfg.sidtab; sidtab; sidtab = sidtab->next) - { ++sidtablength; } - - for(sidtab = cfg.sidtab; sidtab; sidtab = sidtab->next) - { - if(strcmp(sidtab->label, service) == 0) - { - struct s_auth *account; - struct s_client *cl; - struct s_reader *rdr; - - if(!sidtab_prev) - { cfg.sidtab = sidtab->next; } - else - { sidtab_prev->next = sidtab->next; } - - for(account = cfg.account; (account); account = account->next) - { - delete_from_SIDTABBITS(&account->sidtabs.ok, position, sidtablength); - delete_from_SIDTABBITS(&account->sidtabs.no, position, sidtablength); - - for(cl = first_client->next; cl ; cl = cl->next) - { - if(account == cl->account) - { - cl->sidtabs.ok = account->sidtabs.ok; - cl->sidtabs.no = account->sidtabs.no; - } - } - } - - LL_ITER itr = ll_iter_create(configured_readers); - while((rdr = ll_iter_next(&itr))) - { - delete_from_SIDTABBITS(&rdr->sidtabs.ok, position, sidtablength); - delete_from_SIDTABBITS(&rdr->sidtabs.no, position, sidtablength); - delete_from_SIDTABBITS(&rdr->lb_sidtabs.ok, position, sidtablength); - } - free_sidtab(sidtab); - ++counter; - break; - } - sidtab_prev = sidtab; - position++; - } - if(counter > 0) - { - ++cfg_sidtab_generation; - tpl_addMsg(vars, "Service has been deleted!"); - if(write_services() != 0) { tpl_addMsg(vars, "Writing services to disk failed!"); } - } - else { tpl_addMsg(vars, "Sorry but the specified service doesn't exist. No deletion will be made!"); } - } - } - - sidtab = cfg.sidtab; - // Show List - counter = 0; - while(sidtab != NULL) - { - tpl_addVar(vars, TPLADD, "SID", ""); - tpl_printf(vars, TPLADD, "SERVICENUM", "%d", counter + 1); - if((strcmp(getParam(params, "service"), sidtab->label) == 0) && (strcmp(getParam(params, "action"), "list") == 0)) - { - tpl_addVar(vars, TPLADD, "SIDCLASS", "sidlist"); - tpl_addVar(vars, TPLAPPEND, "SID", ""); - for(i = 0; i < sidtab->num_srvid; i++) - { - tpl_printf(vars, TPLAPPEND, "SID", "%04X : %s
", sidtab->srvid[i], - xml_encode(vars, get_servicename(cur_client(), sidtab->srvid[i], sidtab->num_provid ? sidtab->provid[0] : 0, - sidtab->num_caid ? sidtab->caid[0] : 0, channame, sizeof(channame)))); - } - } - else - { - tpl_addVar(vars, TPLADD, "SIDCLASS", ""); - tpl_printf(vars, TPLADD, "SID", "Show Services", urlencode(vars, sidtab->label)); - } - tpl_addVar(vars, TPLADD, "LABELENC", urlencode(vars, sidtab->label)); - tpl_addVar(vars, TPLADD, "LABEL", xml_encode(vars, sidtab->label)); - tpl_addVar(vars, TPLADD, "SIDLIST", tpl_getTpl(vars, "SERVICECONFIGSIDBIT")); - - tpl_addVar(vars, TPLAPPEND, "SERVICETABS", tpl_getTpl(vars, "SERVICECONFIGLISTBIT")); - sidtab = sidtab->next; - counter++; - } - if(counter >= MAX_SIDBITS) - { - tpl_addVar(vars, TPLADD, "BTNDISABLED", "DISABLED"); - tpl_addMsg(vars, "Maximum Number of Services is reached"); - } - return tpl_getTpl(vars, "SERVICECONFIGLIST"); -} - -static char *send_oscam_savetpls(struct templatevars * vars) -{ - if(cfg.http_tpl) - { - tpl_printf(vars, TPLADD, "CNT", "%d", tpl_saveIncludedTpls(cfg.http_tpl)); - tpl_addVar(vars, TPLADD, "PATH", cfg.http_tpl); - } - else { tpl_addVar(vars, TPLADD, "CNT", "0"); } - return tpl_getTpl(vars, "SAVETEMPLATES"); -} - -static char *send_oscam_shutdown(struct templatevars * vars, FILE * f, struct uriparams * params, int8_t apicall, int8_t *keepalive, char *extraheader) -{ - if(!apicall) { setActiveMenu(vars, MNU_SHUTDOWN); } - if(strcmp(strtolower(getParam(params, "action")), "shutdown") == 0) - { - *keepalive = 0; - if(!apicall) - { - char *CSS = tpl_getUnparsedTpl("CSS", 1, ""); - tpl_addVar(vars, TPLADD, "STYLESHEET", CSS); - NULLFREE(CSS); - tpl_printf(vars, TPLADD, "REFRESHTIME", "%d", SHUTDOWNREFRESH); - tpl_addVar(vars, TPLADD, "REFRESH", tpl_getTpl(vars, "REFRESH")); - tpl_printf(vars, TPLADD, "SECONDS", "%d", SHUTDOWNREFRESH); - char *result = tpl_getTpl(vars, "SHUTDOWN"); - send_headers(f, 200, "OK", extraheader, "text/html", 0, cs_strlen(result), NULL, 0); - webif_write(result, f); - cs_log("Shutdown requested by WebIF from %s", cs_inet_ntoa(GET_IP())); - } - else - { - tpl_addVar(vars, TPLADD, "APICONFIRMMESSAGE", "shutdown"); - cs_log("Shutdown requested by XMLApi from %s", cs_inet_ntoa(GET_IP())); - } - cs_exit_oscam(); - - if(!apicall) - { return "1"; } - else - { return tpl_getTpl(vars, "APICONFIRMATION"); } - - } - else if(strcmp(strtolower(getParam(params, "action")), "restart") == 0) - { - *keepalive = 0; - if(!apicall) - { - char *CSS = tpl_getUnparsedTpl("CSS", 1, ""); - tpl_addVar(vars, TPLADD, "STYLESHEET", CSS); - NULLFREE(CSS); - tpl_addVar(vars, TPLADD, "REFRESHTIME", "5"); - tpl_addVar(vars, TPLADD, "REFRESH", tpl_getTpl(vars, "REFRESH")); - tpl_addVar(vars, TPLADD, "SECONDS", "5"); - char *result = tpl_getTpl(vars, "SHUTDOWN"); - send_headers(f, 200, "OK", extraheader, "text/html", 0, cs_strlen(result), NULL, 0); - webif_write(result, f); - cs_log("Restart requested by WebIF from %s", cs_inet_ntoa(GET_IP())); - } - else - { - tpl_addVar(vars, TPLADD, "APICONFIRMMESSAGE", "restart"); - cs_log("Restart requested by XMLApi from %s", cs_inet_ntoa(GET_IP())); - } - cs_restart_oscam(); - - if(!apicall) - { return "1"; } - else - { return tpl_getTpl(vars, "APICONFIRMATION"); } - - } - else - { - return tpl_getTpl(vars, "PRESHUTDOWN"); - } -} - -static char *send_oscam_script(struct templatevars * vars, struct uriparams * params) -{ - setActiveMenu(vars, MNU_SCRIPT); - tpl_printf(vars, TPLADD, "SCRIPTOPTIONS", "\n"); - - if(!cfg.http_readonly && cfg.http_script) - { - struct dirent **namelist; - int count, i; - count = scandir(cfg.http_script, &namelist, 0, alphasort ); - if( count >= 0 ) - { - for( i = 0 ; i < count; i++ ) - { - if(is_ext(namelist[i]->d_name, ".script") || is_ext(namelist[i]->d_name, ".sh")) - { - tpl_printf(vars, TPLAPPEND, "SCRIPTOPTIONS", "\n",namelist[i]->d_name,namelist[i]->d_name); - } - free( namelist[i] ); - } - free(namelist); - } - - char *scriptname = getParam(params, "scriptname"); - char *scriptparam = getParam(params, "scriptparam"); - char system_str[256]; - struct stat s; - snprintf(system_str, sizeof(system_str), "%s/%s", cfg.http_script, scriptname); - - if(!stat(system_str,&s)) - { - if(s.st_mode & S_IFREG) - { - if(s.st_mode & S_IXUSR) - { - int32_t rc = -1; - FILE *fp; - char buf[256]; - - if((scriptparam != NULL) && (sizeof(scriptparam) > 0)) - { - cs_strncat(system_str, " ", sizeof(system_str)); - cs_strncat(system_str, scriptparam, sizeof(system_str)); - } - - fp = popen(system_str, "r"); - if (fp) - { - while (fgets(buf, sizeof(buf), fp) != NULL) - { - tpl_addVar(vars, TPLAPPEND, "SCRIPTRESULTOUT", buf); - } - rc = pclose(fp)/256; - } - - tpl_printf(vars, TPLAPPEND, "CODE", "returncode: %d", rc); - tpl_printf(vars, TPLADD, "SCRIPTNAME", "scriptname: %s", scriptname); - } - else - { - tpl_printf(vars, TPLADD, "SCRIPTRESULTOUT", "[Error]: Script \"%s\" not executable!", scriptname); - } - } - } - else - { - tpl_printf(vars, TPLADD, "SCRIPTRESULTOUT", "[Error]: Script \"%s\" not found!", scriptname); - } - - } - return tpl_getTpl(vars, "SCRIPT"); -} - -static char *send_oscam_scanusb(struct templatevars * vars) -{ - setActiveMenu(vars, MNU_READERS); -#if !defined(__CYGWIN__) - FILE *fp; - char line[100]; - uint8_t i; - char header[11], txt[13], entry[10], bit[8], scan[12], error[120]; - -// key tool package match command - char *elems[] = { "USB", "lsusb", "usbutils", "Bus ", "lsusb -v | egrep '^Bus|^ *iSerial|^ *iProduct'" - , "UDEV", "/dev/serial/by-id", "udev", "<-", "find /dev/serial/by-id -type l -exec readlink -fn {} ';' -exec echo ' <- {}' \\;" -#ifdef CARDREADER_PCSC - , "PCSC", "pcsc_scan", "pcsc-tools", ":", "pcsc_scan -r" -#endif - }; - - for (i = 0; i < (sizeof(elems) / sizeof(elems[0])); i+=5) - { - snprintf(header, sizeof(header), "%sHEADER", elems[i]); //key - snprintf(txt, sizeof(txt), "%s Devices", elems[i]); //key - snprintf(entry, sizeof(entry), "%sENTRY", elems[i]); //key - snprintf(bit, sizeof(bit), "%sBIT", elems[i]); //key - snprintf(scan, sizeof(scan), "SCAN%sBIT", elems[i]); //key - snprintf(error, sizeof(error), "%s: Failed to run or %s package not installed!", elems[i + 1], elems[i + 2]); //tool + package - - tpl_addVar(vars, TPLADD, header, txt); - fp = popen(elems[i + 4], "r"); //command - if(!fp || !fgets(line, sizeof(line) - 1, fp)) - { - tpl_addVar(vars, TPLADD, entry, error); - tpl_addVar(vars, TPLADD, bit, tpl_getTpl(vars, scan)); - } - else - { - do{ - tpl_addVar(vars, TPLADD, "USBENTRYCLASS", ""); - if(strstr(line, elems[i + 3])) //match - { - tpl_addVar(vars, TPLADD, entry, line); - tpl_addVar(vars, TPLADD, "USBENTRYCLASS", "CLASS=\"scanusbsubhead\""); - } - else - { - tpl_printf(vars, TPLADD, entry, "     %s", line); - } - tpl_addVar(vars, TPLAPPEND, bit, tpl_getTpl(vars, scan)); - } - while(fgets(line, sizeof(line) - 1, fp) != NULL); - pclose(fp); - } - } -#else - tpl_addMsg(vars, "Function not supported in CYGWIN environment"); -#endif - return tpl_getTpl(vars, "SCANUSB"); -} - -static void webif_process_logfile(struct templatevars * vars, struct uriparams * params, char *targetfile, size_t targetfile_len) -{ - snprintf(targetfile, targetfile_len, "%s", cfg.logfile); - if(strcmp(getParam(params, "clear"), "logfile") == 0) - { - if(cs_strlen(targetfile) > 0) - { - FILE *file = fopen(targetfile, "w"); - if (file != NULL) - { - fclose(file); - } - } - } -#ifdef WITH_DEBUG - // Debuglevel Selector - int32_t i, lvl; - for(i = 0; i < MAX_DEBUG_LEVELS; i++) - { - lvl = 1 << i; - tpl_printf(vars, TPLADD, "TMPC", "DCLASS%d", lvl); - tpl_printf(vars, TPLADD, "TMPV", "DEBUGVAL%d", lvl); - if(cs_dblevel & lvl) - { - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMPC"), "debugls"); - tpl_printf(vars, TPLADD, tpl_getVar(vars, "TMPV"), "%d", cs_dblevel - lvl); - } - else - { - tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMPC"), "debugl"); - tpl_printf(vars, TPLADD, tpl_getVar(vars, "TMPV"), "%d", cs_dblevel + lvl); - } - } - if(cs_dblevel == D_ALL_DUMP) - { tpl_addVar(vars, TPLADD, "DCLASS65535", "debugls"); } - else - { tpl_addVar(vars, TPLADD, "DCLASS65535", "debugl"); } - tpl_addVar(vars, TPLADD, "CUSTOMPARAM", "&file=logfile"); - tpl_printf(vars, TPLADD, "ACTDEBUG", "%d", cs_dblevel); -#ifdef CS_CACHEEX_AIO - tpl_addVar(vars, TPLADD, "SDEBUG", tpl_getTpl(vars, "DEBUGSELECTAIO")); -#else - tpl_addVar(vars, TPLADD, "SDEBUG", tpl_getTpl(vars, "DEBUGSELECT")); -#endif - tpl_addVar(vars, TPLADD, "NEXTPAGE", "files.html"); -#endif - if(!cfg.disablelog) - { - tpl_printf(vars, TPLADD, "SWITCH", "%d", 1); - tpl_addVar(vars, TPLADD, "TEXT", "Stop Log"); - tpl_addVar(vars, TPLADD, "LOGMENU", tpl_getTpl(vars, "LOGMENUDISABLELOG")); - - } - else - { - tpl_printf(vars, TPLADD, "SWITCH", "%d", 0); - tpl_addVar(vars, TPLADD, "TEXT", "Start Log"); - tpl_addVar(vars, TPLADD, "LOGMENU", tpl_getTpl(vars, "LOGMENUDISABLELOG")); - } - tpl_addVar(vars, TPLAPPEND, "LOGMENU", tpl_getTpl(vars, "CLEARLOG")); - return; -} - -static void webif_process_userfile(struct templatevars * vars, struct uriparams * params, char *targetfile, size_t targetfile_len) -{ - snprintf(targetfile, targetfile_len, "%s", cfg.usrfile); - if(strcmp(getParam(params, "clear"), "usrfile") == 0) - { - if(cs_strlen(targetfile) > 0) - { - FILE *file = fopen(targetfile, "w"); - if (file) - { - fclose(file); - } - } - } - if(!cfg.disableuserfile) - { - tpl_printf(vars, TPLADD, "SWITCH", "%d", 1); - tpl_addVar(vars, TPLADD, "TEXT", "Stop Log"); - tpl_addVar(vars, TPLADD, "LOGMENU", tpl_getTpl(vars, "LOGMENUONOFF")); - } - else - { - tpl_printf(vars, TPLADD, "SWITCH", "%d", 0); - tpl_addVar(vars, TPLADD, "TEXT", "Start Log"); - tpl_addVar(vars, TPLADD, "LOGMENU", tpl_getTpl(vars, "LOGMENUONOFF")); - } - tpl_addVar(vars, TPLAPPEND, "LOGMENU", tpl_getTpl(vars, "CLEARUSERLOG")); - tpl_addVar(vars, TPLADD, "FFVAL", "all"); - tpl_addVar(vars, TPLADD, "FILTERFORMOPTIONS", tpl_getTpl(vars, "LOGMENUFILTERFORM")); - struct s_auth *account; - for(account = cfg.account; account; account = account->next) - { - tpl_addVar(vars, TPLADD, "FFVAL", xml_encode(vars, account->usr)); - tpl_addVar(vars, TPLADD, "FFSEL", strcmp(getParam(params, "filter"), account->usr) ? "" : "selected"); - tpl_addVar(vars, TPLAPPEND, "FILTERFORMOPTIONS", tpl_getTpl(vars, "LOGMENUFILTERFORM")); - } - tpl_addVar(vars, TPLADD, "FILTERFORM", tpl_getTpl(vars, "FILTERFORM")); -} - -enum file_types { FTYPE_CONFIG, FTYPE_VERSION, FTYPE_ANTICASC, FTYPE_LOGFILE, FTYPE_USERFILE , FTYPE_GBOX }; - -struct files -{ - char *file; - int menu_id; - enum file_types type; -}; - -static char *send_oscam_files(struct templatevars * vars, struct uriparams * params, int8_t apicall) -{ - bool writable = false; - const struct files *entry; - static struct files config_files[] = - { - // id are used - // new entry after last entry before first ifdef entry - // ifdef must be add to end - { "oscam.version", MNU_CFG_FVERSION, FTYPE_VERSION }, // id 0 - { "oscam.conf", MNU_CFG_FCONF, FTYPE_CONFIG }, // id 1 - { "oscam.user", MNU_CFG_FUSER, FTYPE_CONFIG }, // id 2 - { "oscam.server", MNU_CFG_FSERVER, FTYPE_CONFIG }, // id 3 - { "oscam.srvid", MNU_CFG_FSRVID, FTYPE_CONFIG }, // id 4 - { "oscam.srvid2", MNU_CFG_FSRVID2, FTYPE_CONFIG }, // id 5 - { "logfile", MNU_CFG_FLOGFILE, FTYPE_LOGFILE }, // id 6 - { "userfile", MNU_CFG_FUSERFILE, FTYPE_USERFILE }, // id 7 - { "css_file_name", MNU_CFG_FCSS, FTYPE_CONFIG }, // id 8 - { "oscam.services", MNU_CFG_FSERVICES, FTYPE_CONFIG }, // id 9 - { "oscam.provid", MNU_CFG_FPROVID, FTYPE_CONFIG }, // id 10 - { "oscam.tiers", MNU_CFG_FTIERS, FTYPE_CONFIG }, // id 11 - { "oscam.ratelimit", MNU_CFG_FRATELIMIT,FTYPE_CONFIG }, // id 12 - { "oscam.whitelist", MNU_CFG_FWHITELIST,FTYPE_CONFIG }, // id 13 -#ifdef HAVE_DVBAPI - { "oscam.dvbapi", MNU_CFG_FDVBAPI, FTYPE_CONFIG }, // id 14 -#endif -#ifdef CS_CACHEEX - { "oscam.fakecws", MNU_CFG_FFAKECWS, FTYPE_CONFIG }, // id 15 -#endif -#ifdef CS_ANTICASC - { "anticasc", MNU_CFG_FACLOG, FTYPE_ANTICASC }, // id 16 -#endif -#ifdef MODULE_SERIAL - { "oscam.twin", MNU_CFG_FTWIN, FTYPE_CONFIG }, // id 17 -#endif -#ifdef MODULE_CONSTCW - { "constant.cw", MNU_CFG_FKEYCW, FTYPE_CONFIG }, // id 18 -#endif -#ifdef MODULE_GBOX - { "sc.info", MNU_GBX_FSCINF, FTYPE_GBOX }, // id 19 - { "share.info", MNU_GBX_FSHRINF, FTYPE_GBOX }, // id 20 - { "share.onl", MNU_GBX_FSHRONL, FTYPE_GBOX }, // id 21 - { "gbox.ver", MNU_GBX_FVERS, FTYPE_GBOX }, // id 22 - { "attack.txt", MNU_GBX_FATTACK, FTYPE_GBOX }, // id 23 - { "gsms.log", MNU_GBX_FSMSLOG, FTYPE_GBOX }, // id 24 - { "gsms.ack", MNU_GBX_FSMSACK, FTYPE_GBOX }, // id 25 - { "gsms.nack", MNU_GBX_FSMSNACK, FTYPE_GBOX }, // id 26 - { "stats.info", MNU_GBX_FSTAINF, FTYPE_GBOX }, // id 27 - { "expired.info", MNU_GBX_FEXPINF, FTYPE_GBOX }, // id 28 - { "info.log", MNU_GBX_INFOLOG, FTYPE_GBOX }, // id 29 -#endif -#ifdef WITH_EMU - { "SoftCam.Key", MNU_CFG_FSOFTCAMKEY,FTYPE_CONFIG }, // id 30 -#endif - { NULL, 0, 0 }, - }; - - if(use_srvid2) - { - config_files[4].menu_id = MNU_CFG_FSRVID2; - config_files[5].menu_id = MNU_CFG_FSRVID; - } - - if(cfg.http_css) - { - if(strchr(cfg.http_css,'/')) - config_files[8].file = strrchr(cfg.http_css, '/')+1; - else if(strchr(cfg.http_css,'\\')) - config_files[8].file = strrchr(cfg.http_css, '\\')+1; - else - config_files[8].file = cfg.http_css; - tpl_addVar(vars, TPLADD, "FILE_USER_CSS", xml_encode(vars, config_files[8].file)); - } - - if(!apicall) { setActiveMenu(vars, MNU_FILES); } - - tpl_addVar(vars, TPLADD, "APIFILENAME", "null"); - tpl_addVar(vars, TPLADD, "APIWRITABLE", "0"); - - if(use_srvid2) - { - tpl_printf(vars, TPLADD, "SRVID", "%s", "oscam.srvid2"); - tpl_printf(vars, TPLADD, "SRVIDSUB", "%s", "oscam.srvid"); - } - else - { - tpl_printf(vars, TPLADD, "SRVID", "%s", "oscam.srvid"); - tpl_printf(vars, TPLADD, "SRVIDSUB", "%s", "oscam.srvid2"); - } - - char *stoplog = getParam(params, "stoplog"); - if(cs_strlen(stoplog) > 0) - { cs_disable_log(atoi(stoplog)); } - - char *stopusrlog = getParam(params, "stopusrlog"); - if(cs_strlen(stopusrlog) > 0) - { cfg.disableuserfile = atoi(stopusrlog); } - - char *debuglvl = getParam(params, "debug"); - if(cs_strlen(debuglvl) > 0) - { -#ifndef WITH_DEBUG - cs_log("*** Warning: Debug Support not compiled in ***"); -#else - int32_t dblvl = atoi(debuglvl); - if(dblvl >= 0 && dblvl <= 65535) { cs_dblevel = dblvl; } - cs_log("%s debug_level=%d", "all", cs_dblevel); -#endif - } - // Process config files - char *file = getParam(params, "file"); - char targetfile[256] = { 0 }; - int menu_id = 0; - for(entry = config_files; entry->file; entry++) - { - if(streq(file, entry->file)) - { - if(!apicall) { setActiveSubMenu(vars, entry->menu_id); } - menu_id = entry->menu_id; - tpl_addVar(vars, TPLADD, "APIWRITABLE", writable ? "1" : "0"); - switch(entry->type) - { - case FTYPE_CONFIG: - writable = 1; - get_config_filename(targetfile, sizeof(targetfile), entry->file); - break; - case FTYPE_VERSION: - get_tmp_dir_filename(targetfile, sizeof(targetfile), entry->file); - break; - case FTYPE_ANTICASC: -#ifdef CS_ANTICASC - if(!apicall) { snprintf(targetfile, sizeof(targetfile), "%s", ESTR(cfg.ac_logfile)); } -#endif - break; - case FTYPE_LOGFILE: - if(!apicall) { webif_process_logfile(vars, params, targetfile, sizeof(targetfile)); } - break; - case FTYPE_USERFILE: - if(!apicall) { webif_process_userfile(vars, params, targetfile, sizeof(targetfile)); } - break; - case FTYPE_GBOX: -#ifdef MODULE_GBOX - get_gbox_filename(targetfile, sizeof(targetfile), entry->file); -#endif - break; - } - tpl_addVar(vars, TPLADD, "APIFILENAME", entry->file); - break; - } - } - - if(cfg.http_css) - { - tpl_addVar(vars, TPLADD, "VIEW_FILEMENUCSS", tpl_getTpl(vars, "FILEMENUCSS")); - } - - if(!strstr(targetfile, "/dev/")) - { - if(strcmp(getParam(params, "action"), "Save") == 0) - { - if((cs_strlen(targetfile) > 0) /*&& (file_exists(targetfile) == 1)*/) - { - FILE *fpsave; - char *fcontent = getParam(params, "filecontent"); - if((fpsave = fopen(targetfile, "w"))) - { - int32_t i, lastpos = 0, len = cs_strlen(fcontent) + 1; - //write submitted file line by line to disk and remove windows linebreaks - for(i = 0; i < len; ++i) - { - char tmp = fcontent[i]; - if(tmp == '\r' || tmp == '\n' || tmp == 0) - { - fcontent[i] = 0; - fprintf(fpsave, "%s%s", fcontent + lastpos, tmp == 0 ? "" : "\n"); - if(tmp == '\r' && fcontent[i + 1] == '\n') { ++i; } - lastpos = i + 1; - } - } - fclose(fpsave); - tpl_addVar(vars, TPLAPPEND, "APIFILENAME", " saved!"); - // Reinit on save - switch(menu_id) - { - case MNU_CFG_FSRVID: - case MNU_CFG_FSRVID2: - init_srvid(); - break; - case MNU_CFG_FPROVID: - init_provid(); - break; - case MNU_CFG_FUSER: - cs_accounts_chk(); - break; - case MNU_CFG_FDVBAPI: - dvbapi_read_priority(); - break; - case MNU_CFG_FWHITELIST: - global_whitelist_read(); - break; - case MNU_CFG_FFAKECWS: - init_fakecws(); - break; - default: - break; - } - } - } - } - - if((cs_strlen(targetfile) > 0) && (file_exists(targetfile) == 1)) - { - FILE *fp; - char buffer[256]; - - if((fp = fopen(targetfile, "r")) == NULL) { return "0"; } - while(fgets(buffer, sizeof(buffer), fp) != NULL) - if(!strcmp(getParam(params, "filter"), "all")) - { tpl_addVar(vars, TPLAPPEND, "FILECONTENT", buffer); } - else if(strstr(buffer, getParam(params, "filter"))) - { tpl_addVar(vars, TPLAPPEND, "FILECONTENT", buffer); } - fclose(fp); - } - else - { - tpl_addVar(vars, TPLAPPEND, "FILECONTENT", "File does not exist or no file selected!"); - } - } - else - { - tpl_addVar(vars, TPLAPPEND, "FILECONTENT", "File not valid!"); - } - - tpl_addVar(vars, TPLADD, "PART", file); - - if(!writable) - { - tpl_addVar(vars, TPLADD, "WRITEPROTECTION", tpl_getTpl(vars, "WRITEPROTECTION")); - tpl_addVar(vars, TPLADD, "BTNDISABLED", "DISABLED"); - } - - if(!apicall) - { return tpl_getTpl(vars, "FILE"); } - else - { return tpl_getTpl(vars, "APIFILE"); } -} - -static char *send_oscam_failban(struct templatevars * vars, struct uriparams * params, int8_t apicall) -{ - IN_ADDR_T ip2delete; - set_null_ip(&ip2delete); - LL_ITER itr = ll_iter_create(cfg.v_list); - V_BAN *v_ban_entry; - //int8_t apicall = 0; //remove before flight - - if(!apicall) { setActiveMenu(vars, MNU_FAILBAN); } - - if(strcmp(getParam(params, "action"), "delete") == 0) - { - if(strcmp(getParam(params, "intip"), "all") == 0) - { - // clear whole list - while(ll_iter_next(&itr)) - { - ll_iter_remove_data(&itr); - } - } - else - { - //we have a single IP - cs_inet_addr(getParam(params, "intip"), &ip2delete); - while((v_ban_entry = ll_iter_next(&itr))) - { - if(IP_EQUAL(v_ban_entry->v_ip, ip2delete)) - { - ll_iter_remove_data(&itr); - break; - } - } - } - } - ll_iter_reset(&itr); - - struct timeb now; - cs_ftime(&now); - - while((v_ban_entry = ll_iter_next(&itr))) - { - tpl_printf(vars, TPLADD, "IPADDRESS", "%s@%d", cs_inet_ntoa(v_ban_entry->v_ip), v_ban_entry->v_port); - tpl_addVar(vars, TPLADD, "VIOLATIONUSER", v_ban_entry->info ? v_ban_entry->info : "unknown"); - struct tm st ; - localtime_r(&v_ban_entry->v_time.time, &st); // fix me, we need walltime! - if(!apicall) - { - tpl_printf(vars, TPLADD, "VIOLATIONDATE", "%02d.%02d.%02d %02d:%02d:%02d", - st.tm_mday, st.tm_mon + 1, - st.tm_year % 100, st.tm_hour, - st.tm_min, st.tm_sec); - } - else - { - char tbuffer [30]; - strftime(tbuffer, 30, "%Y-%m-%dT%H:%M:%S%z", &st); - tpl_addVar(vars, TPLADD, "VIOLATIONDATE", tbuffer); - } - - tpl_printf(vars, TPLADD, "VIOLATIONCOUNT", "%d", v_ban_entry->v_count); - - int64_t gone = comp_timeb(&now, &v_ban_entry->v_time); - if(!apicall) - { - if(!v_ban_entry->acosc_entry) - { tpl_addVar(vars, TPLADD, "LEFTTIME", sec2timeformat(vars, (cfg.failbantime * 60) - (gone / 1000))); } - else - { tpl_addVar(vars, TPLADD, "LEFTTIME", sec2timeformat(vars, v_ban_entry->acosc_penalty_dur - (gone / 1000))); } - } - else - { - if(!v_ban_entry->acosc_entry) - { tpl_printf(vars, TPLADD, "LEFTTIME", "%"PRId64"", (cfg.failbantime * 60) - (gone / 1000)); } - else - { tpl_printf(vars, TPLADD, "LEFTTIME", "%"PRId64"", v_ban_entry->acosc_penalty_dur - (gone / 1000)); } - } - - tpl_addVar(vars, TPLADD, "INTIP", cs_inet_ntoa(v_ban_entry->v_ip)); - - if(!apicall) - { tpl_addVar(vars, TPLAPPEND, "FAILBANROW", tpl_getTpl(vars, "FAILBANBIT")); } - else - { tpl_addVar(vars, TPLAPPEND, "APIFAILBANROW", tpl_getTpl(vars, "APIFAILBANBIT")); } - } - if(!apicall) - { return tpl_getTpl(vars, "FAILBAN"); } - else - { return tpl_getTpl(vars, "APIFAILBAN"); } -} - -static bool send_EMM(struct s_reader * rdr, uint16_t caid, const struct s_cardsystem *csystem, const uint8_t *emmhex, uint32_t len) -{ - if(NULL != rdr && NULL != emmhex && 0 != len) - { - EMM_PACKET *emm_pack = NULL; - - if(cs_malloc(&emm_pack, sizeof(EMM_PACKET))) - { - struct s_client *webif_client = cur_client(); - webif_client->grp = 0xFF; /* to access to all readers */ - - memset(emm_pack, '\0', sizeof(EMM_PACKET)); - emm_pack->client = webif_client; - emm_pack->emmlen = len; - memcpy(emm_pack->emm, emmhex, len); - - emm_pack->caid[0] = (caid >> 8) & 0xFF; - emm_pack->caid[1] = caid & 0xFF; - - if(csystem && csystem->get_emm_type) - { - if(!csystem->get_emm_type(emm_pack, rdr)) - { - rdr_log_dbg(rdr, D_EMM, "get_emm_type() returns error"); - } - } - - cs_log_dbg(D_EMM, "emm is being sent to reader %s.", rdr->label); - add_job(rdr->client, ACTION_READER_EMM, emm_pack, sizeof(EMM_PACKET)); - return true; - } - } - - return false; -} - -static bool process_single_emm(struct templatevars * vars, struct s_reader * rdr, uint16_t caid, const struct s_cardsystem *csystem, const char *ep) -{ - - if(NULL != vars && NULL != rdr && NULL != ep) - { - char emmdata[1025] = {'\0'}; /*1024 + '\0'*/ - uint8_t emmhex[513] = {'\0'}; - char buff[7] = {'\0'}; - uint16_t len = 0; - cs_strncpy(emmdata, ep, sizeof(emmdata)); - remove_white_chars(emmdata); - - if('\0' != emmdata[0]) - { - len = cs_strlen(emmdata); - tpl_addVar(vars, TPLADD, "EP", strtoupper(emmdata)); - if(key_atob_l(emmdata, emmhex, len)) - { - tpl_addMsg(vars, "Single EMM has not been sent due to wrong value!"); - } - else - { - len /= 2; - snprintf(buff, sizeof(buff), "0x%02X", len); - tpl_addVar(vars, TPLADD, "EP", strtoupper(emmdata)); - tpl_addVar(vars, TPLADD, "SIZE", buff); - - if(send_EMM(rdr, caid, csystem, emmhex, len)) - { - tpl_addMsg(vars, "Single EMM has been sent."); - return true; - } - } - } - } - tpl_addVar(vars, TPLADD, "SIZE", "0x00"); - return false; -} - -static bool process_emm_file(struct templatevars * vars, struct s_reader * rdr, uint16_t caid, const struct s_cardsystem *csystem, const char *sFilePath) -{ - - bool bret = false; - uint32_t fsize = 0; - uint32_t rlines = 0; - uint32_t wemms = 0; - uint32_t errsize = 0; - char numerrl[256] = {'\0'}; - char buff[20] = {'\0'}; - - if(NULL != rdr && NULL != sFilePath && '\0' != sFilePath[0]) - { - char sMessage[128] = {0}; - if(true == file_exists(sFilePath)) - { - FILE *fp; - if((fp = fopen(sFilePath, "r"))) - { - char line[2048] = {'\0'}; - uint8_t emmhex[513] = {'\0'}; - uint32_t len = 0; - - tpl_addMsg(vars, "EMM file has been processed."); - while(fgets(line, sizeof(line), fp)) - { - ++rlines; - len = cs_strlen(remove_white_chars(line)); - - // wrong emm - if(len > (sizeof(emmhex) * 2) || - key_atob_l(line, emmhex, len)) - { - errsize += snprintf(numerrl + errsize, sizeof(numerrl) - errsize, "%d, ", rlines); - continue; - } - len /= 2; - if(send_EMM(rdr, caid, csystem, emmhex, len)) - { - ++wemms; - int32_t jcount = ll_count(rdr->client->joblist); - if (jcount > 200) - { - /* Give more time to process EMMs */ - cs_sleepms(1000); - } - rdr_log_dbg(rdr, D_READER, "pending emm jobs: %i, processed emms: %i", jcount, wemms); - } - } - fsize = ftell(fp); - fclose(fp); - } - else - { - snprintf(sMessage, sizeof(sMessage), "Cannot open file '%s' (errno=%d: %s)\n", sFilePath, errno, strerror(errno)); - tpl_addMsg(vars, sMessage); - } - } - else - { - snprintf(sMessage, sizeof(sMessage), "FILE \"%s\" not found!", sFilePath); - tpl_addMsg(vars, sMessage); - } - bret = true; - } - - snprintf(buff, sizeof(buff), "%d bytes", fsize); - tpl_addVar(vars, TPLADD, "FSIZE", buff); - snprintf(buff, sizeof(buff), "%d", rlines); - tpl_addVar(vars, TPLADD, "NUMRLINE", buff); - snprintf(buff, sizeof(buff), "%d", wemms); - tpl_addVar(vars, TPLADD, "NUMWEMM", buff); - tpl_addVar(vars, TPLADD, "ERRLINE", numerrl); - - return bret; -} - -static char *send_oscam_EMM_running(struct templatevars * vars, struct uriparams * params) -{ - - struct s_reader *rdr = NULL; - - setActiveMenu(vars, MNU_READERS); - tpl_addVar(vars, TPLADD, "READER", getParam(params, "label")); - tpl_addVar(vars, TPLADD, "FNAME", getParam(params, "emmfile")); - - rdr = get_reader_by_label(getParam(params, "label")); - if(rdr) - { - int32_t tcaid = dyn_word_atob(getParam(params, "emmcaid")); - uint16_t caid = (-1 != tcaid) ? (uint16_t)tcaid : 0; - char buff[7] = ""; - const struct s_cardsystem *csystem = NULL; - int32_t proxy = is_cascading_reader(rdr); - - if((proxy || !rdr->csystem_active) && caid) // network reader (R_CAMD35 R_NEWCAMD R_CS378X R_CCCAM) - { - if(proxy && !rdr->ph.c_send_emm) - { - tpl_addMsg(vars, "The reader does not support EMM's!"); - return tpl_getTpl(vars, "EMM_RUNNING"); - } - - csystem = get_cardsystem_by_caid(caid); - if(!csystem) - { - rdr_log_dbg(rdr, D_EMM, "unable to find cardsystem for caid %04X", caid); - caid = 0; - } - } - else if(!proxy && rdr->csystem_active) // local active reader - { - csystem = rdr->csystem; - - if(rdr->typ != R_EMU) - { - caid = rdr->caid; - } - } - - if(csystem) - { - tpl_addVar(vars, TPLADD, "SYSTEM", csystem->desc); - } - else - { - tpl_addVar(vars, TPLADD, "SYSTEM", "unknown"); - } - if(caid) - { - snprintf(buff, sizeof(buff), "0x%04X", caid); - tpl_addVar(vars, TPLADD, "CAID", buff); - } - else - { - tpl_addVar(vars, TPLADD, "CAID", "unknown"); - } - - process_single_emm(vars, rdr, caid, csystem, getParam(params, "ep")); - process_emm_file(vars, rdr, caid, csystem, getParam(params, "emmfile")); - } - else - { - char sMessage[128] = {0}; - snprintf(sMessage, sizeof(sMessage), "READER \"%s\" not found!", getParam(params, "label")); - tpl_addMsg(vars, sMessage); - tpl_addVar(vars, TPLADD, "READER", "reader not found"); - } - - return tpl_getTpl(vars, "EMM_RUNNING"); -} - -static char *send_oscam_EMM(struct templatevars * vars, struct uriparams * params) -{ - - setActiveMenu(vars, MNU_READERS); - tpl_addVar(vars, TPLADD, "READER", getParam(params, "label")); - - struct s_reader *rdr = NULL; - rdr = get_reader_by_label(getParam(params, "label")); - if(rdr && rdr->caid) - { - char buff[5] = ""; - snprintf(buff, sizeof(buff), "%04X", rdr->caid); - tpl_addVar(vars, TPLADD, "CAID", buff); - if(!is_cascading_reader(rdr)) - { - tpl_addVar(vars, TPLADD, "READONLY", "readonly=\"readonly\""); - } - } - - FILE *fp; - struct stat sb; - char buffer[1024]; - char emm_hex[1024]; - char filename[128]; - char targetfile[256]; - char tmpstr[20]; - char emm_txt[32]; - char emm_title[32]; - char *emm_path; - char *emm_types[] = { "unique_emm", "shared_emm", "global_emm" }; - char *emm_names[] = { "RDREMMUNIQUE", "RDREMMSHARED", "RDREMMGLOBAL" }; - char *emm_cfg_names[] = { "httpemmuclean", "httpemmsclean", "httpemmgclean" }; - int32_t emm_max_size[] = { cfg.http_emmu_clean, cfg.http_emms_clean, cfg.http_emmg_clean }; - int num_emm_types = 3; - int i; - - emm_path = cfg.emmlogdir ? cfg.emmlogdir : cs_confdir; - - for( i = 0 ; i < num_emm_types; i++ ) - { - snprintf(filename, sizeof(filename), "%s%s%s%s", getParam(params, "label"), "_", emm_types[i], ".log"); - snprintf(targetfile, sizeof(targetfile), "%s%s%s", emm_path, emm_path[cs_strlen(emm_path) - 1] == '/' ? "" : "/", filename); - snprintf(emm_txt, sizeof(emm_txt), "%s_TXT", emm_names[i]); - tpl_addVar(vars, TPLADD, emm_txt, filename); - - if((fp = fopen(targetfile, "r")) != NULL) - { - stat(targetfile, &sb); - tpl_printf(vars, TPLAPPEND, emm_txt, " (Size: %'.2f kB)", (double)sb.st_size/1024); - - if(emm_max_size[i]>=0) - { - snprintf(emm_title, sizeof(emm_title), "%s_TITLE", emm_names[i]); - tpl_addVar(vars, TPLADD, emm_title, "title=\"Click Line to Copy EMM in Single EMM Write Field\""); - } - - if(emm_max_size[i]>0) - { - uint32_t emms=0, emm_d, emmrs=0; - char *ptr, *saveptr1 = NULL; - - while(fgets(buffer, sizeof(buffer), fp) != NULL) - { - emms++; - snprintf(tmpstr, sizeof(tmpstr), "LINE_%d", emms); - tpl_addVar(vars, TPLADD, tmpstr, buffer); - } - - for(emm_d=emms;emm_d>0;--emm_d) - { - snprintf(tmpstr, sizeof(tmpstr), "LINE_%d", emm_d); - if(sscanf(tpl_getVar(vars, tmpstr), "%*s %*s %*s %s", &emm_hex[0])==1) - { - if(strstr(tpl_getVar(vars, "EMM_TMP"),emm_hex)==0) - { tpl_addVar(vars, TPLAPPEND, "EMM_TMP", tpl_getVar(vars, tmpstr)); } - tpl_addVar(vars, TPLADD, tmpstr, ""); - } - } - - for(ptr = strtok_r(tpl_getVar(vars, "EMM_TMP"),"\n", &saveptr1); ptr; ptr = strtok_r(NULL,"\n", &saveptr1)) - { - emmrs++; - snprintf(tmpstr, sizeof(tmpstr), "LINE_%d", emmrs); - tpl_addVar(vars, TPLADD, tmpstr, ptr); - } - tpl_addVar(vars, TPLADD, "EMM_TMP", ""); - - tpl_printf(vars, TPLAPPEND, emm_txt, ": %'d different EMM's from a total of %'d Entries", emmrs,emms); - for(emm_d=emmrs;emm_d>0;--emm_d) - { - snprintf(tmpstr, sizeof(tmpstr), "LINE_%d", emm_d); - tpl_printf(vars, TPLAPPEND, emm_names[i], "%s\n", tpl_getVar(vars, tmpstr)); - if(sb.st_size>emm_max_size[i]*1024) { tpl_printf(vars, TPLAPPEND, "EMM_TMP", "%s\n", tpl_getVar(vars, tmpstr)); } - tpl_addVar(vars, TPLADD, tmpstr, ""); - } - - if(sb.st_size>emm_max_size[i]*1024) - { - char orgfile[268]; - int f=0; - do { - snprintf(orgfile, sizeof(orgfile), "%s.%d", targetfile, f); - f++; - } while(access(orgfile, F_OK) != -1); - - if(rename(targetfile, orgfile) == 0) - { - FILE *fs = fopen(targetfile, "w"); - if (fs) - { - fprintf(fs, "%s", tpl_getVar(vars, "EMM_TMP")); - fclose(fs); - } - tpl_printf(vars, TPLAPPEND, emm_txt, "
New reduced File created! Size of Original File is higher as %d kB, saved to %s", emm_max_size[i], orgfile); - } - } - tpl_addVar(vars, TPLADD, "EMM_TMP", ""); - } - else if (emm_max_size[i]==0) - { - while(fgets(buffer, sizeof(buffer), fp) != NULL) - { - tpl_printf(vars, TPLAPPEND, emm_names[i], "%s", buffer); - } - } - else - { - tpl_printf(vars, TPLADD, emm_names[i],"Viewing of EMM File deactivated.
Set %s in Config Webif to 0 or higher for viewing or filtering EMM File.", emm_cfg_names[i]); - } - fclose(fp); - } - if(strcmp(tpl_getVar(vars, emm_names[i]),"")==0) { tpl_addVar(vars, TPLADD, emm_names[i],"no saved EMM's"); } - } - - return tpl_getTpl(vars, "ASKEMM"); -} - -#ifdef CS_CACHEEX -static uint64_t get_cacheex_node(struct s_client * cl) -{ - uint64_t node = 0x00; -#if defined(MODULE_CCCAM) || defined(MODULE_CAMD35) || defined(MODULE_CAMD35_TCP) - struct s_module *module = (cl->reader ? &cl->reader->ph : get_module(cl)); -#endif -#ifdef MODULE_CCCAM - if(module->num == R_CCCAM && cl->cc) - { - struct cc_data *cc = cl->cc; - memcpy(&node, cc->peer_node_id, 8); - } - else -#endif -#ifdef MODULE_CAMD35 - if(module->num == R_CAMD35) - { - memcpy(&node, cl->ncd_skey, 8); - } - else -#endif -#ifdef MODULE_CAMD35_TCP - if(module->num == R_CS378X) - { - memcpy(&node, cl->ncd_skey, 8); - } - else -#endif - {} - return node; -} - - -static char *send_oscam_cacheex(struct templatevars * vars, struct uriparams * params, int8_t apicall) -{ - - if(!apicall) { setActiveMenu(vars, MNU_CACHEEX); } - - if(strcmp(getParam(params, "x"), "x") == 0) - { - // avoid compilerwarning unused vars - } - char *level[] = {"NONE", "CACHE PULL", "CACHE PUSH", "REVERSE CACHE PUSH"}; - char *getting = "\"Getting\""; - char *pushing = "\"Pushing\""; - char *rowvariable = ""; - - int16_t written = 0; -#ifdef CS_CACHEEX_AIO - int16_t i = 0; -#endif - struct s_client *cl; - time_t now = time((time_t *)0); - int delimiter=0; - - if(!apicall) - { - if(strcmp(getParam(params, "action"), "resetallcacheexstats") == 0) - { - cacheex_clear_all_stats(); - } - } - - tpl_printf(vars, TPLADD, "OWN_CACHEEX_NODEID", "%" PRIu64 "X", cacheex_node_id(cacheex_peer_id)); - - const char *cacheex_name_link_tpl = NULL; - tpl_addVar(vars, TPLADD, "CLIENTDESCRIPTION", ""); - - for(cl = first_client; cl ; cl = cl->next) - { -#ifdef CS_CACHEEX_AIO - i++; - char classname[9]; - snprintf(classname, 8, "class%02d", i) < 0 ? abort() : (void)0; - classname[8] = '\0'; - tpl_addVar(vars, TPLADD, "CLASSNAME", classname); -#endif - - if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode) - { - cacheex_name_link_tpl = "SUSER"; - tpl_addVar(vars, TPLADD, "TYPE", "Client"); - if(!apicall) - { - tpl_addVar(vars, TPLADD, "USERNAME", xml_encode(vars, cl->account->usr)); - tpl_addVar(vars, TPLADD, "USERENC", urlencode(vars, cl->account->usr)); - - if(cl->account->description) - { - tpl_printf(vars, TPLADD, "CLIENTDESCRIPTION","%s(%s)",!apicall?" ":"",xml_encode(vars, cl->account->description)); - } - else - { - tpl_addVar(vars, TPLADD, "CLIENTDESCRIPTION", ""); - } - } - else - { - tpl_addVar(vars, TPLADD, "NAME", cl->account->usr); - - if(cl->account->description) - { - tpl_addVar(vars, TPLADD, "CLIENTDESCRIPTION", cl->account->description); - } - else - { - tpl_addVar(vars, TPLADD, "CLIENTDESCRIPTION", ""); - } - } - - if(IP_ISSET(cl->ip)) - { tpl_addVar(vars, TPLADD, "IP", cs_inet_ntoa(cl->ip)); } - else if(cl->login > cl->logout) - { tpl_addVar(vars, TPLADD, "IP", "camd.socket"); } - else - { tpl_addVar(vars, TPLADD, "IP", ""); } - tpl_printf(vars, TPLADD, "NODE", "%" PRIu64 "X", get_cacheex_node(cl)); - tpl_addVar(vars, TPLADD, "LEVEL", level[cl->account->cacheex.mode]); - tpl_printf(vars, TPLADD, "PUSH", "%d", cl->account->cwcacheexpush); - tpl_printf(vars, TPLADD, "GOT", "%d", cl->account->cwcacheexgot); - tpl_printf(vars, TPLADD, "CWCINFO", "%d", cl->account->cwc_info); - tpl_printf(vars, TPLADD, "HIT", "%d", cl->account->cwcacheexhit); - tpl_printf(vars, TPLADD, "ERR", "%d", cl->account->cwcacheexerr); - tpl_printf(vars, TPLADD, "ERRCW", "%d", cl->account->cwcacheexerrcw); -#ifdef CS_CACHEEX_AIO - tpl_printf(vars, TPLADD, "GOTLG", "%d", cl->account->cwcacheexgotlg); - tpl_printf(vars, TPLADD, "PUSHLG", "%d", cl->account->cwcacheexpushlg); - tpl_printf(vars, TPLADD, "REL_CACHEXHITGOT", "%.2f", (double)(cl->account->cwcacheexhit ? (double)cl->account->cwcacheexhit : 0) * 100 / (double)(cl->account->cwcacheexgot ? cl->account->cwcacheexgot : 1)); -#endif - tpl_addVar(vars, TPLADD, "DIRECTIONIMG", (cl->account->cacheex.mode == 3) ? getting : pushing); - rowvariable = "TABLECLIENTROWS"; - written = 1; - } - else if((cl->typ == 'p' || cl->typ == 'r') && (cl->reader && cl->reader->cacheex.mode)) - { - cacheex_name_link_tpl = "SREADER"; - tpl_addVar(vars, TPLADD, "TYPE", "Reader"); - - if(!apicall) - { - tpl_addVar(vars, TPLADD, "READERNAME", xml_encode(vars, cl->reader->label)); - tpl_addVar(vars, TPLADD, "READERNAMEENC", urlencode(vars, cl->reader->label)); - - if(cl->reader->description) - { - tpl_printf(vars, TPLADD, "CLIENTDESCRIPTION","%s(%s)",!apicall?" ":"",xml_encode(vars, cl->reader->description)); - } - else - { - tpl_addVar(vars, TPLADD, "CLIENTDESCRIPTION", ""); - } - } - else - { - tpl_addVar(vars, TPLADD, "NAME", cl->reader->label); - - if(cl->reader->description) - { - tpl_addVar(vars, TPLADD, "CLIENTDESCRIPTION", cl->reader->description); - } - else - { - tpl_addVar(vars, TPLADD, "CLIENTDESCRIPTION", ""); - } - } - - if(IP_ISSET(cl->ip)) - { tpl_addVar(vars, TPLADD, "IP", cs_inet_ntoa(cl->ip)); } - else if(cl->reader && cl->reader->tcp_connected) - { tpl_addVar(vars, TPLADD, "IP", "camd.socket"); } - else - { tpl_addVar(vars, TPLADD, "IP", ""); } - tpl_printf(vars, TPLADD, "NODE", "%" PRIu64 "X", get_cacheex_node(cl)); - tpl_addVar(vars, TPLADD, "LEVEL", level[cl->reader->cacheex.mode]); - tpl_printf(vars, TPLADD, "PUSH", "%d", cl->cwcacheexpush); - tpl_printf(vars, TPLADD, "CWCINFO", "%d", cl->cwc_info); - tpl_printf(vars, TPLADD, "GOT", "%d", cl->cwcacheexgot); - tpl_printf(vars, TPLADD, "CWCINFO", "%d", cl->cwc_info); - tpl_printf(vars, TPLADD, "HIT", "%d", cl->cwcacheexhit); - tpl_printf(vars, TPLADD, "ERR", "%d", cl->cwcacheexerr); - tpl_printf(vars, TPLADD, "ERRCW", "%d", cl->cwcacheexerrcw); -#ifdef CS_CACHEEX_AIO - tpl_printf(vars, TPLADD, "GOTLG", "%d", cl->cwcacheexgotlg); - tpl_printf(vars, TPLADD, "PUSHLG", "%d", cl->cwcacheexpushlg); - tpl_printf(vars, TPLADD, "REL_CACHEXHITGOT", "%.2f", (double)(cl->cwcacheexhit ? (double)cl->cwcacheexhit : 0) * 100 / (double)(cl->cwcacheexgot ? cl->cwcacheexgot : 1)); -#endif - tpl_addVar(vars, TPLADD, "DIRECTIONIMG", (cl->reader->cacheex.mode == 3) ? pushing : getting); - - rowvariable = "TABLEREADERROWS"; - written = 1; - } - else if(get_module(cl)->listenertype == LIS_CSPUDP) - { - cacheex_name_link_tpl = "SREADER"; - tpl_addVar(vars, TPLADD, "TYPE", "csp"); - - if(!apicall) - { - tpl_addVar(vars, TPLADD, "READERNAME", "csp"); - tpl_addVar(vars, TPLADD, "READERNAMEENC", "csp"); - } - else - { - tpl_addVar(vars, TPLADD, "NAME", "csp"); - } - - if(IP_ISSET(cl->ip)) - { tpl_addVar(vars, TPLADD, "IP", cs_inet_ntoa(cl->ip)); } - else if(cl->login > cl->logout) - { tpl_addVar(vars, TPLADD, "IP", "camd.socket"); } - else - { tpl_addVar(vars, TPLADD, "IP", ""); } - tpl_addVar(vars, TPLADD, "NODE", "csp"); - - if(cl->cwcacheexping) - { - tpl_printf(vars, TPLADD, "LEVEL", "csp (%d ms)", cl->cwcacheexping); - } - else - { - tpl_addVar(vars, TPLADD, "LEVEL", "csp"); - } - - tpl_printf(vars, TPLADD, "PUSH", "%d", cl->cwcacheexpush); - tpl_printf(vars, TPLADD, "GOT", "%d", cl->cwcacheexgot); - tpl_printf(vars, TPLADD, "HIT", "%d", cl->cwcacheexhit); - tpl_printf(vars, TPLADD, "ERR", "%d", cl->cwcacheexerr); - tpl_printf(vars, TPLADD, "ERRCW", "%d", cl->cwcacheexerrcw); -#ifdef CS_CACHEEX_AIO - tpl_printf(vars, TPLADD, "GOTLG", "%d", cl->cwcacheexgotlg); - tpl_printf(vars, TPLADD, "PUSHLG", "%d", cl->cwcacheexpushlg); - tpl_printf(vars, TPLADD, "REL_CACHEXHITGOT", "%.2f", (double)(cl->cwcacheexhit ? (double)cl->cwcacheexhit : 0) * 100 / (double)(cl->cwcacheexgot ? cl->cwcacheexgot : 1)); -#endif - tpl_addVar(vars, TPLADD, "DIRECTIONIMG", getting); - rowvariable = "TABLECLIENTROWS"; - written = 1; - } - - if(written) - { - if(!apicall) - { - tpl_addVar(vars, TPLADD, "NAME", tpl_getTpl(vars, cacheex_name_link_tpl)); - } -#ifdef CS_CACHEEX_AIO - tpl_addVar(vars, TPLAPPEND, rowvariable, tpl_getTpl(vars, "CACHEEXAIOTABLEROW")); -#else - tpl_addVar(vars, TPLAPPEND, rowvariable, tpl_getTpl(vars, "CACHEEXTABLEROW")); -#endif - - if(cl->ll_cacheex_stats) - { - LL_ITER itr = ll_iter_create(cl->ll_cacheex_stats); - S_CACHEEX_STAT_ENTRY *cacheex_stats_entry; - - while((cacheex_stats_entry = ll_iter_next(&itr))) - { - tpl_addVar(vars, TPLADD, "DIRECTIONIMG", ""); - if(now - cacheex_stats_entry->cache_last < 20) - { tpl_addVar(vars, TPLADD, "TYPE", cacheex_stats_entry->cache_direction == 0 ? pushing : getting); } - else - { tpl_addVar(vars, TPLADD, "TYPE", ""); } - tpl_printf(vars, TPLADD, "NAME", "%04X@%06X:%04X", cacheex_stats_entry->cache_caid, - cacheex_stats_entry->cache_prid, - cacheex_stats_entry->cache_srvid); - if(cacheex_stats_entry->cache_direction == 0) - { - tpl_printf(vars, TPLADD, "PUSH", "%d", cacheex_stats_entry->cache_count); -#ifdef CS_CACHEEX_AIO - tpl_printf(vars, TPLADD, "PUSHLG", "%d", cacheex_stats_entry->cache_count_lg); -#endif - tpl_addVar(vars, TPLADD, "GOT", ""); - } - else - { - tpl_printf(vars, TPLADD, "GOT", "%d", cacheex_stats_entry->cache_count); -#ifdef CS_CACHEEX_AIO - tpl_printf(vars, TPLADD, "GOTLG", "%d", cacheex_stats_entry->cache_count_lg); -#endif - tpl_addVar(vars, TPLADD, "PUSH", ""); - } - tpl_addVar(vars, TPLADD, "HIT", ""); - char channame[CS_SERVICENAME_SIZE]; - char *lastchan = xml_encode(vars, get_servicename(cl, cacheex_stats_entry->cache_srvid, cacheex_stats_entry->cache_prid, cacheex_stats_entry->cache_caid, channame, sizeof(channame))); - tpl_addVar(vars, TPLADD, "LEVEL", lastchan); - if (apicall == 2) - { - tpl_printf(vars, TPLADD, "JSONDELIMITER", "%s", (delimiter > 1)?",":""); -#ifdef CS_CACHEEX_AIO - tpl_addVar(vars, TPLAPPEND, "JSONCACHEEXBITS", tpl_getTpl(vars, "JSONCACHEEXAIOBIT")); -#else - tpl_addVar(vars, TPLAPPEND, "JSONCACHEEXBITS", tpl_getTpl(vars, "JSONCACHEEXBIT")); -#endif - delimiter++; - } - else - { -#ifdef CS_CACHEEX_AIO - tpl_addVar(vars, TPLAPPEND, rowvariable, tpl_getTpl(vars, "CACHEEXAIOTABLEROWSTATS")); -#else - tpl_addVar(vars, TPLAPPEND, rowvariable, tpl_getTpl(vars, "CACHEEXTABLEROW")); -#endif - } - } - } - written = 0; - } - } - - float cachesum = first_client ? first_client->cwcacheexgot : 1; - if(cachesum < 1) - { - cachesum = 1; - } - tpl_printf(vars, TPLADD, "TOTAL_CACHEXPUSH", PRINTF_LOCAL_D, first_client ? first_client->cwcacheexpush : 0); - tpl_addVar(vars, TPLADD, "TOTAL_CACHEXPUSH_IMG", pushing); - tpl_printf(vars, TPLADD, "TOTAL_CACHEXGOT", PRINTF_LOCAL_D, first_client ? first_client->cwcacheexgot : 0); - tpl_addVar(vars, TPLADD, "TOTAL_CACHEXGOT_IMG", getting); - tpl_printf(vars, TPLADD, "TOTAL_CACHEXHIT", PRINTF_LOCAL_D, first_client ? first_client->cwcacheexhit : 0); - tpl_printf(vars, TPLADD, "TOTAL_CACHESIZE", "%d", cache_size()); -#ifdef CS_CACHEEX_AIO - tpl_printf(vars, TPLADD, "TOTAL_CACHESIZE_LG", "%d", cache_size_lg()); -#endif - - tpl_printf(vars, TPLADD, "REL_CACHEXHIT", "%.2f", (first_client ? first_client->cwcacheexhit : 0) * 100 / cachesum); - - if(!apicall) - { -#ifdef CS_CACHEEX_AIO - return tpl_getTpl(vars, "CACHEEXAIOPAGE"); -#else - return tpl_getTpl(vars, "CACHEEXPAGE"); -#endif - } - else - { - return tpl_getTpl(vars, "JSONCACHEEX"); - } -} -#endif - -#ifdef WEBIF_WIKI -static char *send_oscam_wiki(struct templatevars *vars, struct uriparams *params) -{ - const char *config = getParam(params, "config"); - const char *section = getParam(params, "section"); - const char *param = getParam(params, "param"); - - if(!config || !param || !config[0] || !param[0]) - { - return tpl_getTpl(vars, "WIKIERROR"); - } - - const char *text = wiki_get_help(config, section, param); - - if(text) - { - tpl_addVar(vars, TPLADD, "WIKIPARAM", param); - tpl_addVar(vars, TPLADD, "WIKICONFIG", config); - tpl_addVar(vars, TPLADD, "WIKITEXT", json_encode(vars, text)); - return tpl_getTpl(vars, "WIKIJSON"); - } - else - { - tpl_addVar(vars, TPLADD, "WIKIPARAM", param); - tpl_addVar(vars, TPLADD, "WIKICONFIG", config); - return tpl_getTpl(vars, "WIKINOTFOUND"); - } -} - -static char *send_oscam_wiki_status(struct templatevars *vars, struct uriparams *params) -{ - const char *config = getParam(params, "config"); - - if(!config || !config[0]) - { - return tpl_getTpl(vars, "WIKIERROR"); - } - - /* Build JSON object with status for all params in this config */ - char json_buf[8192]; - int pos = 0; - int32_t i, count = wiki_count(); - bool first = true; - - pos += snprintf(json_buf + pos, sizeof(json_buf) - pos, "{"); - -#ifdef COMPRESSED_WIKI - /* For compressed wiki, we iterate through entries but access via decompressed data */ - const struct wiki_entry *entries = wiki_get_entries(); - char *wiki_data = wiki_get_decompressed_data(); - - if(wiki_data) - { - for(i = 0; i < count && pos < (int)sizeof(json_buf) - 100; i++) - { - const char *e_config = wiki_data + entries[i].config_ofs; - const char *e_param = wiki_data + entries[i].param_ofs; - - if(strcmp(e_config, config) != 0) - { continue; } - - /* Section filter is optional - include all params from this config */ - if(!first) - { pos += snprintf(json_buf + pos, sizeof(json_buf) - pos, ","); } - first = false; - - const char *status_str = "ok"; - if(entries[i].status == 1) status_str = "review"; - else if(entries[i].status == 2) status_str = "missing"; - - pos += snprintf(json_buf + pos, sizeof(json_buf) - pos, "\"%s\":\"%s\"", - e_param, status_str); - } - } -#else - const struct wiki_entry *entries = wiki_get_entries(); - for(i = 0; i < count && pos < (int)sizeof(json_buf) - 100; i++) - { - if(strcmp(entries[i].config, config) != 0) - { continue; } - - /* Section filter is optional - include all params from this config */ - if(!first) - { pos += snprintf(json_buf + pos, sizeof(json_buf) - pos, ","); } - first = false; - - const char *status_str = "ok"; - if(entries[i].status == 1) status_str = "review"; - else if(entries[i].status == 2) status_str = "missing"; - - pos += snprintf(json_buf + pos, sizeof(json_buf) - pos, "\"%s\":\"%s\"", - entries[i].param, status_str); - } -#endif - - pos += snprintf(json_buf + pos, sizeof(json_buf) - pos, "}"); - - tpl_addVar(vars, TPLADD, "WIKISTATUS", json_buf); - return tpl_getTpl(vars, "WIKISTATUSJSON"); -} -#endif - -static char *send_oscam_api(struct templatevars * vars, FILE * f, struct uriparams * params, int8_t *keepalive, int8_t apicall, char *extraheader) -{ - if(strcmp(getParam(params, "part"), "status") == 0) - { - return send_oscam_status(vars, params, apicall); - } - else if(strcmp(getParam(params, "part"), "userstats") == 0) - { - return send_oscam_user_config(vars, params, apicall); - } - else if(strcmp(getParam(params, "part"), "failban") == 0) - { - return send_oscam_failban(vars, params, apicall); - } -#ifdef CS_CACHEEX - else if(strcmp(getParam(params, "part"), "cacheex") == 0) - { - return send_oscam_cacheex(vars, params, apicall); - } -#endif - else if(strcmp(getParam(params, "part"), "files") == 0) - { - return send_oscam_files(vars, params, apicall); - } - else if(strcmp(getParam(params, "part"), "readerlist") == 0) - { - return send_oscam_reader(vars, params, apicall); - } - else if(strcmp(getParam(params, "part"), "serverconfig") == 0) - { - //Send Errormessage - tpl_addVar(vars, TPLADD, "APIERRORMESSAGE", "serverconfig not yet avail"); - return tpl_getTpl(vars, "APIERROR"); - } - else if(strcmp(getParam(params, "part"), "userconfig") == 0) - { - if(((strcmp(getParam(params, "action"), "Save") == 0) || - (strcmp(getParam(params, "action"), "Save As") == 0)) && cfg.http_readonly == 1) - { - //Send Errormessage - tpl_addVar(vars, TPLADD, "APIERRORMESSAGE", "API is in readonly mode"); - return tpl_getTpl(vars, "APIERROR"); - } - else - { - struct s_auth *account = get_account_by_name(getParam(params, "user")); - if(!account && strcmp(getParam(params, "action"), "Save")) - { - //Send Errormessage - tpl_addVar(vars, TPLADD, "APIERRORMESSAGE", "user not exist"); - return tpl_getTpl(vars, "APIERROR"); - } - else - { - return send_oscam_user_config_edit(vars, params, apicall); - } - } - } - else if(strcmp(getParam(params, "part"), "entitlement") == 0) - { - - if(strcmp(getParam(params, "label"), "")) - { - struct s_reader *rdr = get_reader_by_label(getParam(params, "label")); - if(rdr) - { - if(rdr->enable == 1) - { - return send_oscam_entitlement(vars, params, apicall); - } - else - { - //Send Errormessage - tpl_addVar(vars, TPLADD, "APIERRORMESSAGE", "no cccam reader or disabled"); - return tpl_getTpl(vars, "APIERROR"); - } - } - else - { - //Send Errormessage - tpl_addVar(vars, TPLADD, "APIERRORMESSAGE", "reader not exist"); - return tpl_getTpl(vars, "APIERROR"); - } - } - else - { - //Send Errormessage - tpl_addVar(vars, TPLADD, "APIERRORMESSAGE", "no reader selected"); - return tpl_getTpl(vars, "APIERROR"); - } - } - else if(strcmp(getParam(params, "part"), "ecmhistory") == 0) - { - int32_t isec; - int32_t shown; - time_t now = time((time_t *)0); - const char *usr; - struct s_client *cl; - for(cl = first_client; cl ; cl = cl->next) - { - if(cl->wihidden != 1) - { - isec = now - cl->lastecm; - usr = username(cl); - shown = 0; - if(strcmp(getParam(params, "label"), "") == 0) - { - if(strcmp(getParam(params, "type"), "servers") == 0) - { - if(cl->typ == 'p' || cl->typ == 'r') - { shown = 1; } - } - else if(strcmp(getParam(params, "type"), "users") == 0) - { - if(cl->typ == 'c') - { shown = 1; } - } - else - { - shown = 1; - } - } - else if(strcmp(getParam(params, "label"), usr) == 0) - { - shown = 1; - } - if(shown == 1) - { - tpl_printf(vars, TPLADD, "CLIENTTYPE", "%c", cl->typ); - tpl_addVar(vars, TPLADD, "CLIENTUSER", xml_encode(vars, usr)); - if(cl->typ == 'c' || cl->typ == 'm') - { - tpl_addVar(vars, TPLADD, "CLIENTDESCRIPTION", xml_encode(vars, cl->account->description ? cl->account->description : "")); - } - else if(cl->typ == 'p' || cl->typ == 'r') - { - tpl_addVar(vars, TPLADD, "CLIENTDESCRIPTION", xml_encode(vars, cl->reader->description ? cl->reader->description : "")); - } - tpl_printf(vars, TPLADD, "CLIENTLASTRESPONSETIME", "%d", cl->cwlastresptime ? cl->cwlastresptime : -1); - tpl_printf(vars, TPLADD, "CLIENTIDLESECS", "%d", isec); - - //load historical values from ringbuffer - char *value = get_ecm_fullhistorystring(cl); - tpl_addVar(vars, TPLADD, "CLIENTLASTRESPONSETIMEHIST", value); - free_mk_t(value); - - tpl_addVar(vars, TPLAPPEND, "APISTATUSBITS", tpl_getTpl(vars, "APISTATUSBIT")); - } - } - } - return tpl_getTpl(vars, "APISTATUS"); - } - else if(strcmp(getParam(params, "part"), "readerstats") == 0) - { - if(strcmp(getParam(params, "label"), "")) - { - struct s_reader *rdr = get_reader_by_label(getParam(params, "label")); - if(rdr) - { - return send_oscam_reader_stats(vars, params, apicall); - } - else - { - //Send Errormessage - tpl_addVar(vars, TPLADD, "APIERRORMESSAGE", "reader not exist"); - return tpl_getTpl(vars, "APIERROR"); - } - } - else - { - //Send Errormessage - tpl_addVar(vars, TPLADD, "APIERRORMESSAGE", "no reader selected"); - return tpl_getTpl(vars, "APIERROR"); - } - } -#ifdef READER_VIDEOGUARD - else if(strcmp(getParam(params, "part"), "sendcmd") == 0) - { - if(strcmp(getParam(params, "label"), "")) - { - struct s_reader *rdr = get_reader_by_label(getParam(params, "label")); - if(rdr) - { - char api_msg[150]; - CMD_PACKET *cmd_pack = NULL; - if(!cs_malloc(&cmd_pack, sizeof(CMD_PACKET))) - { - tpl_addVar(vars, TPLADD, "APIERRORMESSAGE", "cs_malloc failed!"); - return tpl_getTpl(vars, "APIERROR"); - } - struct s_client *webif_client = cur_client(); - webif_client->grp = 0xFF; // access all readers - - memset(cmd_pack, '0', sizeof(CMD_PACKET)); - cmd_pack->client = webif_client; - cmd_pack->cmdlen = strlen(getParam(params, "cmd")) / 2; - - if(cmd_pack->cmdlen > 0 && (unsigned long)abs(cmd_pack->cmdlen) <= sizeof(cmd_pack->cmd)) - { - if(key_atob_l(getParam(params, "cmd"), cmd_pack->cmd, cmd_pack->cmdlen*2)) - { - tpl_addVar(vars, TPLADD, "APIERRORMESSAGE", "'cmd' has not been sent due to wrong value!"); - return tpl_getTpl(vars, "APIERROR"); - } - } - else - { - if(cmd_pack->cmdlen) - { - snprintf(api_msg, sizeof(api_msg), "Command would exceed %lu bytes!", (long unsigned int)sizeof(cmd_pack->cmd)); - tpl_addVar(vars, TPLADD, "APIERRORMESSAGE", api_msg); - } - else - { - tpl_addVar(vars, TPLADD, "APIERRORMESSAGE", "Missing parameter 'cmd'!"); - } - return tpl_getTpl(vars, "APIERROR"); - } - - struct s_client *cl = rdr->client; - if(rdr->enable == 1 && cl && cl->typ == 'r') - { - add_job(cl, ACTION_READER_SENDCMD, cmd_pack, sizeof(CMD_PACKET)); - tpl_addVar(vars, TPLADD, "APICONFIRMMESSAGE", "command sent"); - return tpl_getTpl(vars, "APICONFIRMATION"); - } - else - { - snprintf(api_msg, sizeof(api_msg), "Reader '%s' is not suitable!", xml_encode(vars, rdr->label)); - tpl_addVar(vars, TPLADD, "APIERRORMESSAGE", api_msg); - return tpl_getTpl(vars, "APIERROR"); - } - } - else - { - //Send Errormessage - tpl_addVar(vars, TPLADD, "APIERRORMESSAGE", "no such reader"); - return tpl_getTpl(vars, "APIERROR"); - } - } - else - { - //Send Errormessage - tpl_addVar(vars, TPLADD, "APIERRORMESSAGE", "no reader selected"); - return tpl_getTpl(vars, "APIERROR"); - } - } -#endif - else if(strcmp(getParam(params, "part"), "shutdown") == 0) - { - if((strcmp(strtolower(getParam(params, "action")), "restart") == 0) || - (strcmp(strtolower(getParam(params, "action")), "shutdown") == 0)) - { - if(!cfg.http_readonly) - { - return send_oscam_shutdown(vars, f, params, apicall, keepalive, extraheader); - } - else - { - tpl_addVar(vars, TPLADD, "APIERRORMESSAGE", "webif readonly mode"); - return tpl_getTpl(vars, "APIERROR"); - } - } - else - { - tpl_addVar(vars, TPLADD, "APIERRORMESSAGE", "missing parameter action"); - return tpl_getTpl(vars, "APIERROR"); - } - - } - else - { - tpl_addVar(vars, TPLADD, "APIERRORMESSAGE", "part not found"); - return tpl_getTpl(vars, "APIERROR"); - } -} - -static char *send_oscam_image(struct templatevars * vars, FILE * f, struct uriparams * params, char *image, time_t modifiedheader, uint32_t etagheader, char *extraheader) -{ - char *wanted; - if(image == NULL) { wanted = getParam(params, "i"); } - else { wanted = image; } - if(cs_strlen(wanted) > 3 && wanted[0] == 'I' && wanted[1] == 'C') - { - if(etagheader == 0) - { - int8_t disktpl = 0; - char *tpl_path; - tpl_path = cfg.http_piconpath? cfg.http_piconpath : cfg.http_tpl; - - if(tpl_path) - { - char path[255]; - if(cs_strlen(tpl_getTplPath(wanted, tpl_path, path, 255)) > 0 && file_exists(path)) - { - struct stat st; - disktpl = 1; - stat(path, &st); - if((time_t)st.st_mtime < modifiedheader) - { - send_header304(f, extraheader); - return "1"; - } - } - } - if(disktpl == 0 && first_client->login < modifiedheader) - { - send_header304(f, extraheader); - return "1"; - } - } - char *header = strstr(tpl_getTpl(vars, wanted), "data:"); - if(header != NULL) - { - char *ptr = header + 5; - while(ptr[0] != ';' && ptr[0] != '\0') { ++ptr; } - if(ptr[0] != '\0' && ptr[1] != '\0') { ptr[0] = '\0'; } - else { return "0"; } - ptr = strstr(ptr + 1, "base64,"); - if(ptr != NULL) - { - int32_t len = b64decode((uint8_t *)ptr + 7); - if(len > 0) - { - if((uint32_t)crc32(0L, (uint8_t *)ptr + 7, len) == etagheader) - { - send_header304(f, extraheader); - } - else - { - send_headers(f, 200, "OK", extraheader, header + 5, 1, len, ptr + 7, 0); - webif_write_raw(ptr + 7, f, len); - } - return "1"; - } - } - } - } - // Return file not found - const char *not_found = "File not found.\n"; - send_headers(f, 404, "Not Found", extraheader, "text/plain", 0, cs_strlen(not_found), (char *)not_found, 0); - webif_write_raw((char *)not_found, f, cs_strlen(not_found)); - return "1"; -} - -static char *send_oscam_robots_txt(FILE * f) -{ - const char *content = "User-agent: *\nDisallow: /\n"; - send_headers(f, 200, "OK", NULL, "text/plain", 0, cs_strlen(content), (char *)content, 0); - webif_write_raw((char *)content, f, cs_strlen(content)); - return "1"; -} - -static char *send_oscam_graph(struct templatevars * vars) -{ - return tpl_getTpl(vars, "GRAPH"); -} - -#ifdef MODULE_GHTTP -static bool ghttp_autoconf(struct templatevars * vars, struct uriparams * params) -{ - int8_t i = 0; - struct s_reader *rdr; - char *name = getParam(params, "gacname"); - if(cs_strlen(name) < 3) - { - tpl_addMsg(vars, "Invalid host name!"); - return false; - } - - LL_ITER itr = ll_iter_create(configured_readers); - while((rdr = ll_iter_next(&itr))) - if(rdr->ph.num == R_GHTTP) { i++; } // count existing ghttp readers - - while(i < 3) // if less than 3, add more - { - char lbl[128]; - snprintf(lbl, sizeof(lbl), "%s%d", "ghttp", i + 1); - cs_log("GHttp autoconf: adding reader %s", lbl); - struct s_reader *newrdr; - if(!cs_malloc(&newrdr, sizeof(struct s_reader))) - { - tpl_addMsg(vars, "Create reader failed!"); - return false; - }; - newrdr->typ = R_GHTTP; - cs_strncpy(newrdr->label, lbl, sizeof(newrdr->label)); - module_reader_set(newrdr); - reader_set_defaults(newrdr); - newrdr->enable = 0; - newrdr->grp = 1; - ll_append(configured_readers, newrdr); - i++; - } - - uint16_t port = 0; - char *str = strstr(name, ":"); - if(str) - { - port = atoi(str + 1); - str[0] = '\0'; - } - - i = 0; - itr = ll_iter_create(configured_readers); - while((rdr = ll_iter_next(&itr))) - { - if(rdr->ph.num == R_GHTTP) - { - if(i > 2) // remove superflous - { - cs_log("GHttp autoconf: removing reader %s", rdr->label); - inactivate_reader(rdr); - ll_iter_remove(&itr); - free_reader(rdr); - } - else // reconfigure the 3 first ghttp readers - { - cs_log("GHttp autoconf: reconfiguring reader %s", rdr->label); - snprintf(rdr->label, sizeof(rdr->label), "%s%d", "ghttp", i + 1); - rdr->r_port = port; - rdr->enable = 1; - rdr->ghttp_use_ssl = 0; -#ifdef WITH_SSL - rdr->ghttp_use_ssl = 1; -#endif - if(rdr->grp < 1) { rdr->grp = 1; } - cs_strncpy(rdr->r_usr, getParam(params, "gacuser"), sizeof(rdr->r_usr)); - cs_strncpy(rdr->r_pwd, getParam(params, "gacpasswd"), sizeof(rdr->r_pwd)); - if(i == 0) { cs_strncpy(rdr->device, name, sizeof(rdr->device)); } - else - { - if(!strstr(name, ".")) - { snprintf(rdr->device, sizeof(rdr->device), "%s%d", name, i); } // name, name1, name2 - else { cs_strncpy(rdr->device, name, sizeof(rdr->device)); } - // . in the name = assume full hostname = use same for all 3 readers - } - if(i == 2) { rdr->fallback = 1; } - else { rdr->fallback = 0; } - i++; - } - } - } - cs_log("GHttp autoconf: Saving %d readers", i); - if(write_server() != 0) { tpl_addMsg(vars, "Write Config failed!"); } - itr = ll_iter_create(configured_readers); - while((rdr = ll_iter_next(&itr))) - { - if(rdr->ph.num == R_GHTTP) - { restart_cardreader(rdr, 1); } - } - return true; -} - -static char *send_oscam_ghttp(struct templatevars * vars, struct uriparams * params, int8_t apicall) -{ - if(strcmp(strtolower(getParam(params, "action")), "autoconf") == 0) - { - if(!apicall) - { - bool missing = false; - if(cs_strlen(getParam(params, "gacuser")) == 0) - { - tpl_addVar(vars, TPLADD, "USERREQ", "(Required)"); - missing = true; - } - else { tpl_addVar(vars, TPLADD, "GACUSER", getParam(params, "gacuser")); } - if(cs_strlen(getParam(params, "gacpasswd")) == 0) - { - tpl_addVar(vars, TPLADD, "PWDREQ", "(Required)"); - missing = true; - } - else { tpl_addVar(vars, TPLADD, "GACPASSWD", getParam(params, "gacpasswd")); } - if(cs_strlen(getParam(params, "gacname")) == 0) - { - tpl_addVar(vars, TPLADD, "NAMEREQ", "(Required)"); - missing = true; - } - else { tpl_addVar(vars, TPLADD, "GACNAME", getParam(params, "gacname")); } - if(missing) { return tpl_getTpl(vars, "PREAUTOCONF"); } - cs_log("GHttp autoconf requested by WebIF from %s", cs_inet_ntoa(GET_IP())); - } - else - { - tpl_addVar(vars, TPLADD, "APICONFIRMMESSAGE", "autoconf"); - cs_log("GHttp autoconf requested by XMLApi from %s", cs_inet_ntoa(GET_IP())); - } - - if(ghttp_autoconf(vars, params)) - { - tpl_printf(vars, TPLADD, "REFRESHTIME", "%d", 3); - tpl_addVar(vars, TPLADD, "REFRESH", tpl_getTpl(vars, "REFRESH")); - tpl_printf(vars, TPLADD, "SECONDS", "%d", 3); - if(apicall) { return tpl_getTpl(vars, "APICONFIRMATION"); } - else { return tpl_getTpl(vars, "AUTOCONF"); } - } - else { return tpl_getTpl(vars, "PREAUTOCONF"); } // something failed - - } - else - { - if(cs_strlen(getParam(params, "token")) > 0) // parse autoconf token - { - char *token = getParam(params, "token"); - int32_t len = b64decode((uint8_t *)token); - if(len > 0) - { - struct uriparams tokenprms; - tokenprms.paramcount = 0; - parseParams(&tokenprms, token); - if(cs_strlen(getParam(&tokenprms, "u")) > 0) - { - tpl_addVar(vars, TPLADD, "GACUSER", getParam(&tokenprms, "u")); - tpl_addVar(vars, TPLADD, "USERRDONLY", "readonly"); - } - if(cs_strlen(getParam(&tokenprms, "p")) > 0) - { - tpl_addVar(vars, TPLADD, "GACPASSWD", getParam(&tokenprms, "p")); - tpl_addVar(vars, TPLADD, "PWDRDONLY", "readonly"); - } - if(cs_strlen(getParam(&tokenprms, "n")) > 0) - { - tpl_addVar(vars, TPLADD, "GACNAME", getParam(&tokenprms, "n")); - tpl_addVar(vars, TPLADD, "NAMERDONLY", "readonly"); - } - } - } - return tpl_getTpl(vars, "PREAUTOCONF"); - } -} -#endif - -static int8_t check_httpip(IN_ADDR_T addr) -{ - int8_t i = 0; - // check all previously dyndns resolved addresses - for(i = 0; i < MAX_HTTP_DYNDNS; i++) - { - if(IP_ISSET(cfg.http_dynip[i]) && IP_EQUAL(cfg.http_dynip[i], addr)) - { return 1; } - } - return 0; -} - -static int8_t check_httpdyndns(IN_ADDR_T addr) -{ - - // check all previously dyndns resolved addresses - if(check_httpip(addr)) - { return 1; } - - // we are not ok, so resolve all dyndns entries into IP's - maybe outdated IP's - - if(cfg.http_dyndns[0][0]) - { - int8_t i = 0; - for(i = 0; i < MAX_HTTP_DYNDNS; i++) - { - if(cfg.http_dyndns[i][0]) - { - cs_resolve((const char *)cfg.http_dyndns[i], &cfg.http_dynip[i], NULL, NULL); - cs_log_dbg(D_TRACE, "WebIf: httpdyndns [%d] resolved %s to %s ", i, (char *)cfg.http_dyndns[i], cs_inet_ntoa(cfg.http_dynip[i])); - } - } - } - else - { - cs_log_dbg(D_TRACE, "WebIf: No dyndns addresses found"); - return 0; - } - - // again check all dyndns resolved addresses - if(check_httpip(addr)) - { return 1; } - - return 0; -} - -static int8_t check_valid_origin(IN_ADDR_T addr) -{ - - // check whether requesting IP is in allowed IP ranges - if(check_ip(cfg.http_allowed, addr)) - { return 1; } - - // we havn't found the requesting IP in allowed range. So we check for allowed httpdyndns as last chance - if(cfg.http_dyndns[0][0]) - { - int8_t ok; - ok = check_httpdyndns(addr); - return ok; - } - return 0; -} - -static int8_t check_request(char *result, int32_t readen) -{ - if(readen < 50) { return 0; } - result[readen] = '\0'; - int8_t method; - if(strncmp(result, "POST", 4) == 0) { method = 1; } - else { method = 0; } - char *headerEnd = strstr(result, "\r\n\r\n"); - if(headerEnd == NULL) { return 0; } - else if(method == 0) { return 1; } - else - { - char *ptr = strstr(result, "Content-Length: "); - if(ptr != NULL) - { - ptr += 16; - if(ptr < result + readen) - { - uint32_t length = atoi(ptr); - if(cs_strlen(headerEnd + 4) >= length) { return 1; } - } - } - } - return 0; -} - -static int32_t readRequest(FILE * f, IN_ADDR_T in, char **result, int8_t forcePlain) -{ - int32_t n, bufsize = 0, errcount = 0; - char buf2[1024]; - struct pollfd pfd2[1]; -#ifdef WITH_SSL - int8_t is_ssl = 0; - if(ssl_active && !forcePlain) - { is_ssl = 1; } -#endif - - while(1) - { - errno = 0; - if(forcePlain) - { n = read(fileno(f), buf2, sizeof(buf2)); } - else - { n = webif_read(buf2, sizeof(buf2), f); } - if(n <= 0) - { - if((errno == 0 || errno == EINTR)) - { - if(errcount++ < 10) - { - cs_sleepms(5); - continue; - } - else { return -1; } - } -#ifdef WITH_SSL - if(is_ssl) - { - if(errno != ECONNRESET) - { - int32_t errcode = ERR_peek_error(); - char errstring[128]; - ERR_error_string_n(errcode, errstring, sizeof(errstring) - 1); - cs_log_dbg(D_TRACE, "WebIf: read error ret=%d (%d%s%s)", n, SSL_get_error(cur_ssl(), n), errcode ? " " : "", errcode ? errstring : ""); - } - return -1; - } -#else - if(errno != ECONNRESET) - { cs_log_dbg(D_TRACE, "WebIf: read error ret=%d (errno=%d %s)", n, errno, strerror(errno)); } -#endif - return -1; - } - if(!cs_realloc(result, bufsize + n + 1)) - { - send_error500(f); - NULLFREE(*result); - return -1; - } - - memcpy(*result + bufsize, buf2, n); - bufsize += n; - -#ifdef WITH_EMU - if(bufsize > 204800) // max request size 200kb -#else - if(bufsize > 102400) // max request size 100kb -#endif - { - cs_log("error: too much data received from %s", cs_inet_ntoa(in)); - NULLFREE(*result); - *result = NULL; - return -1; - } - -#ifdef WITH_SSL - if(ssl_active && !forcePlain) - { - int32_t len = 0; - len = SSL_pending((SSL *)f); - - if(len > 0) - { continue; } - - pfd2[0].fd = SSL_get_fd((SSL *)f); - - } - else -#endif - pfd2[0].fd = fileno(f); - - pfd2[0].events = (POLLIN | POLLPRI); - - int32_t rc = poll(pfd2, 1, 100); - if(rc > 0 || !check_request(*result, bufsize)) - { continue; } - else - { break; } - } - return bufsize; -} -static int32_t process_request(FILE * f, IN_ADDR_T in) -{ - int32_t ok = 0; - int8_t *keepalive = (int8_t *)pthread_getspecific(getkeepalive); - IN_ADDR_T addr = GET_IP(); - - do - { -#ifdef WITH_SSL - if(!ssl_active && *keepalive) { fflush(f); } -#else - if(*keepalive) { fflush(f); } -#endif - - // at this point we do all checks related origin IP, ranges and dyndns stuff - ok = check_valid_origin(addr); - cs_log_dbg(D_TRACE, "WebIf: Origin checked. Result: access from %s => %s", cs_inet_ntoa(addr), (!ok) ? "forbidden" : "allowed"); - - // based on the failed origin checks we send a 403 to calling browser - if(!ok) - { - send_error(f, 403, "Forbidden", NULL, "Access denied.", 0); - cs_log("unauthorized access from %s - invalid ip or dyndns", cs_inet_ntoa(addr)); - return 0; - } - int32_t authok = 0; - char expectednonce[(MD5_DIGEST_LENGTH * 2) + 1], opaque[(MD5_DIGEST_LENGTH * 2) + 1]; - char authheadertmp[sizeof(AUTHREALM) + sizeof(expectednonce) + sizeof(opaque) + 100]; - - char *method, *path, *protocol, *str1, *saveptr1 = NULL, *authheader = NULL, *extraheader = NULL, *filebuf = NULL; - char *pch, *tmp, *buf, *nameInUrl, subdir[32]; - /* List of possible pages */ - char *pages[] = - { - "/config.html", - "/readers.html", - "/entitlements.html", - "/status.html", - "/userconfig.html", - "/readerconfig.html", - "/services.html", - "/user_edit.html", - "/site.css", - "/services_edit.html", - "/savetemplates.html", - "/shutdown.html", - "/script.html", - "/scanusb.html", - "/files.html", - "/readerstats.html", - "/failban.html", - "/oscam.js", - "/oscamapi.html", - "/image", - "/favicon.ico", - "/graph.svg", - "/oscamapi.xml", - "/cacheex.html", - "/oscamapi.json", - "/emm.html", - "/emm_running.html", - "/robots.txt", - "/ghttp.html", - "/logpoll.html", - "/jquery.js", -#ifdef WEBIF_WIKI - "/wiki.json", - "/wiki_status.json", -#endif - }; - - int32_t pagescnt = sizeof(pages) / sizeof(char *); // Calculate the amount of items in array - int32_t i, bufsize, len, pgidx = -1; - uint32_t etagheader = 0; - struct uriparams params; - params.paramcount = 0; - time_t modifiedheader = 0; - - bufsize = readRequest(f, in, &filebuf, 0); - - if(!filebuf || bufsize < 1) - { - if(!*keepalive) { cs_log_dbg(D_CLIENT, "WebIf: No data received from client %s. Closing connection.", cs_inet_ntoa(addr)); } - return -1; - } - - buf = filebuf; - - if((method = strtok_r(buf, " ", &saveptr1)) != NULL) - { - if((path = strtok_r(NULL, " ", &saveptr1)) != NULL) - { - if((protocol = strtok_r(NULL, "\r", &saveptr1)) == NULL) - { - NULLFREE(filebuf); - return -1; - } - } - else - { - NULLFREE(filebuf); - return -1; - } - } - else - { - NULLFREE(filebuf); - return -1; - } - tmp = protocol + cs_strlen(protocol) + 2; - - pch = path; - /* advance pointer to beginning of query string */ - while(pch[0] != '?' && pch[0] != '\0') { ++pch; } - if(pch[0] == '?') - { - pch[0] = '\0'; - ++pch; - } - - nameInUrl = pch - 1; - while(nameInUrl != path && nameInUrl[0] != '/') { --nameInUrl; } - - /* allow only alphanumeric sub-folders */ - int32_t subdirLen = nameInUrl - path; - subdir[0] = '\0'; - if(subdirLen > 0 && subdirLen < 32) - { - cs_strncpy(subdir, path + 1, subdirLen); - - int32_t invalidSubdir = 0; - for(i = 0; i < subdirLen - 1; i++) - { - if(!((subdir[i] >= '0' && subdir[i] <= '9') - || (subdir[i] >= 'a' && subdir[i] <= 'z') - || (subdir[i] >= 'A' && subdir[i] <= 'Z'))) - { - - invalidSubdir = 1; - subdir[0] = '\0'; - break; - } - } - - if(!invalidSubdir) - { - subdir[subdirLen] = '\0'; -#ifdef WIN32 - subdir[subdirLen - 1] = '\\'; -#else - subdir[subdirLen - 1] = '/'; -#endif - } - } - - /* Map page to our static page definitions */ - for(i = 0; i < pagescnt; i++) - { - if(!strcmp(nameInUrl, pages[i])) { pgidx = i; } - } - - parseParams(¶ms, pch); - - if(!cfg.http_user || !cfg.http_pwd) - { authok = 1; } - - for(str1 = strtok_r(tmp, "\n", &saveptr1); str1; str1 = strtok_r(NULL, "\n", &saveptr1)) - { - len = cs_strlen(str1); - if(str1[len - 1] == '\r') - { - str1[len - 1] = '\0'; - --len; - } - if(len == 0) - { - if(strcmp(method, "POST") == 0) - { - parseParams(¶ms, str1 + 2); - } - break; - } - if(!authok && len > 50 && strncasecmp(str1, "Authorization:", 14) == 0 && strstr(str1, "Digest") != NULL) - { - if(cs_dblevel & D_CLIENT) - { - if(cs_realloc(&authheader, len + 1)) - { cs_strncpy(authheader, str1, len); } - } - authok = check_auth(str1, method, path, addr, expectednonce, opaque); - } - else if(len > 40 && strncasecmp(str1, "If-Modified-Since:", 18) == 0) - { - modifiedheader = parse_modifiedsince(str1); - } - else if(len > 20 && strncasecmp(str1, "If-None-Match:", 14) == 0) - { - for(pch = str1 + 14; pch[0] != '"' && pch[0] != '\0'; ++pch) { ; } - if(cs_strlen(pch) > 5) { etagheader = (uint32_t)strtoul(++pch, NULL, 10); } - } - else if(len > 12 && strncasecmp(str1, "Connection: Keep-Alive", 22) == 0 && strcmp(method, "POST")) - { - *keepalive = 1; - } - } - - if(cfg.http_user && cfg.http_pwd) - { - if (!authok || cs_strlen(opaque) != MD5_DIGEST_LENGTH * 2) - { - calculate_opaque(addr, opaque); - } - - if (authok != 2) - { - if(!authok) - { - if(authheader) - { - cs_log_dbg(D_CLIENT, "WebIf: Received wrong auth header from %s:", cs_inet_ntoa(addr)); - cs_log_dbg(D_CLIENT, "%s", authheader); - } - else - { cs_log_dbg(D_CLIENT, "WebIf: Received no auth header from %s.", cs_inet_ntoa(addr)); } - } - calculate_nonce(NULL, expectednonce, opaque); - } - - if (authok != 1) - { - snprintf(authheadertmp, sizeof(authheadertmp), "WWW-Authenticate: Digest algorithm=\"MD5\", realm=\"%s\", qop=\"auth\", opaque=\"%s\", nonce=\"%s\"", AUTHREALM, opaque, expectednonce); - if (authok == 2) - { - if (!cs_strncat(authheadertmp, ", stale=true", sizeof(authheadertmp))) { - cs_log("WARNING, bug here!"); - } - } - } - else - { - snprintf(authheadertmp, sizeof(authheadertmp), "Authentication-Info: nextnonce=\"%s\"", expectednonce); - } - - extraheader = authheadertmp; - - if (authok != 1) - { - char *msg = "Access denied.\n"; - send_headers(f, 401, "Unauthorized", extraheader, "text/html", 0, cs_strlen(msg), msg, 0); - webif_write(msg, f); - NULLFREE(authheader); - NULLFREE(filebuf); - if (*keepalive) { - continue; - } else { - return 0; - } - } - } - else - { - NULLFREE(authheader); - } - - /*build page*/ - if(pgidx == 8) - { - send_file(f, "CSS", subdir, modifiedheader, etagheader, extraheader); - } - else if(pgidx == 17) - { - send_file(f, "JS", subdir, modifiedheader, etagheader, extraheader); - } - else if(pgidx == 30) - { - send_file(f, "JQ", subdir, modifiedheader, etagheader, extraheader); - } - else - { - time_t t; - struct templatevars *vars = tpl_create(); - if(vars == NULL) - { - send_error500(f); - NULLFREE(filebuf); - return 0; - } - - tpl_addVar(vars, TPLADD, "SUBDIR", subdir); - - struct tm lt, st; - time(&t); - - localtime_r(&t, <); - - tpl_addVar(vars, TPLADD, "SCM_URL", SCM_URL); - tpl_addVar(vars, TPLADD, "WIKI_URL", WIKI_URL); - tpl_addVar(vars, TPLADD, "BOARD_URL", BOARD_URL); -#ifdef WEBIF_WIKI - tpl_addVar(vars, TPLADD, "WIKIINTERNALVAR", "\t\tvar wikiInternal = true;"); -#else - tpl_addVar(vars, TPLADD, "WIKIINTERNALVAR", ""); -#endif - tpl_addVar(vars, TPLADD, "CS_VERSION", CS_VERSION); - tpl_addVar(vars, TPLADD, "CS_GIT_COMMIT", CS_GIT_COMMIT); - tpl_addVar(vars, TPLADD, "CS_TARGET", CS_TARGET); - tpl_addVar(vars, TPLADD, "HTTPOSCAMLABEL", xml_encode(vars,cfg.http_oscam_label)); - if (!boxtype_is("generic")) - { - if (!boxname_is("generic")) - tpl_printf(vars, TPLADD, "DETECTED_BOXTYPE", "%s (%s)", boxtype_get(), boxname_get()); - else - tpl_addVar(vars, TPLADD, "DETECTED_BOXTYPE", boxtype_get()); - } - - if(cfg.http_locale){ - float decimal_point = 0.0; - setlocale(LC_ALL, cfg.http_locale); - tpl_printf(vars, TPLADD, "TMP_DECPOINT", "%.1f", decimal_point); - tpl_addVar(vars, TPLADD, "LOCALE_DECPOINT", strstr(tpl_getVar(vars, "TMP_DECPOINT"), ",") ? ",": "."); - } - - tpl_addVar(vars, TPLADD, "HTTP_CHARSET", "UTF-8"); - if(cfg.http_picon_size > 0) - { - tpl_printf(vars, TPLADD, "HTTPPICONSIZEINS", "img.statususericon, img.protoicon, img.usericon, img.readericon {height:%dpx !important;max-height:%dpx !important;}", cfg.http_picon_size, cfg.http_picon_size); - } - if(cfg.poll_refresh > 0) - { - tpl_printf(vars, TPLADD, "POLLREFRESHTIME", "%d", cfg.poll_refresh); - } - if ( cfg.http_refresh > 0 && - ((( pgidx == 1 || pgidx == 4 ) && !cfg.poll_refresh ) || - ( pgidx == 3 && ( cfg.http_status_log || !cfg.poll_refresh )) || - pgidx == 15 || pgidx == 23 || pgidx == -1 )) // wenn polling bei cachex.html eingeführt wird muss die 23 => 2 zeilen höher - { - tpl_printf(vars, TPLADD, "REFRESHTIME", "%d", cfg.http_refresh); - tpl_addVar(vars, TPLADD, "WITHQUERY", pgidx == 15 ? "1" : "0"); - tpl_addVar(vars, TPLADD, "REFRESH", tpl_getTpl(vars, "REFRESH")); - } -#ifdef WEBIF_JQUERY - tpl_printf(vars, TPLADD, "SRCJQUERY", "jquery.js?v=%s", CS_VERSION); -#else - tpl_addVar(vars, TPLADD, "SRCJQUERY", cfg.http_extern_jquery); -#endif - - if(picon_exists("LOGO")||cs_strlen(tpl_getTpl(vars, "IC_LOGO"))>3) - { - tpl_addVar(vars, TPLADD, "LOGO_INS", tpl_getTpl(vars, "LOGOBITIMG")); - } - else - { - tpl_addVar(vars, TPLADD, "LOGO_INS", tpl_getTpl(vars, "LOGOBITSVG")); - } - tpl_addVar(vars, TPLADD, "LOGO", tpl_getTpl(vars, "LOGOBIT")); - tpl_printf(vars, TPLADD, "CURDATE", "%02d.%02d.%02d", lt.tm_mday, lt.tm_mon + 1, lt.tm_year % 100); - tpl_printf(vars, TPLADD, "CURTIME", "%02d:%02d:%02d", lt.tm_hour, lt.tm_min, lt.tm_sec); - localtime_r(&first_client->login, &st); - tpl_printf(vars, TPLADD, "STARTDATE", "%02d.%02d.%02d", st.tm_mday, st.tm_mon + 1, st.tm_year % 100); - tpl_printf(vars, TPLADD, "STARTTIME", "%02d:%02d:%02d", st.tm_hour, st.tm_min, st.tm_sec); - tpl_printf(vars, TPLADD, "PROCESSID", "%d", getppid()); - tpl_addVar(vars, TPLADD, "RUNAS", urlencode(vars, username(first_client))); - - time_t now = time((time_t *)0); - // XMLAPI - if(pgidx == 18 || pgidx == 22 || pgidx == 24) - { - char tbuffer [30]; - strftime(tbuffer, 30, "%Y-%m-%dT%H:%M:%S%z", &st); - tpl_addVar(vars, TPLADD, "APISTARTTIME", tbuffer); - tpl_printf(vars, TPLADD, "APIRUNTIME", "%" PRId64, (int64_t)now - first_client->login); - tpl_printf(vars, TPLADD, "APIREADONLY", "%d", cfg.http_readonly); - if(strcmp(getParam(¶ms, "callback"), "")) - { - tpl_printf(vars, TPLADD, "CALLBACK", "%s%s", getParam(¶ms, "callback"), "("); - tpl_addVar(vars, TPLADD, "ENDBRACKET", ")"); - } - - } - - if (config_enabled(WITH_LB)) - tpl_addVar(vars, TPLADD, "LBISDEFINED", "1"); - - // language code in helplink - tpl_addVar(vars, TPLADD, "LANGUAGE", cfg.http_help_lang); - tpl_addVar(vars, TPLADD, "RUNTIME", sec2timeformat(vars, (now - first_client->login))); - time_t uptime = oscam_get_uptime(); - if(uptime > 0){ - tpl_printf(vars, TPLADD, "UPTIMETXT", "%s Up Time: ", strcmp(tpl_getVar(vars, "DETECTED_BOXTYPE"),"")==0 ? "System" : tpl_getVar(vars, "DETECTED_BOXTYPE")); - tpl_addVar(vars, TPLADD, "UPTIME", sec2timeformat(vars, uptime)); - } - tpl_addVar(vars, TPLADD, "CURIP", cs_inet_ntoa(addr)); - if(cfg.http_readonly) - { tpl_addVar(vars, TPLAPPEND, "BTNDISABLED", "DISABLED"); } - - i = ll_count(cfg.v_list); - if(i > 0) { tpl_printf(vars, TPLADD, "FAILBANNOTIFIER", "%d", i); } - tpl_printf(vars, TPLADD, "FAILBANNOTIFIERPOLL", "%d", i); - - char *result = NULL; - - // WebIf allows modifying many things. Thus, all pages except images/css/static are expected to be non-threadsafe! - if(pgidx != 19 && pgidx != 20 && pgidx != 21 && pgidx != 27) { cs_writelock(__func__, &http_lock); } - switch(pgidx) - { - case 0: - tpl_addVar(vars, TPLADD, "CONFIG_CONTENT", send_oscam_config(vars, ¶ms)); - result = tpl_getTpl(vars, "CONFIGCONTENT"); - break; - case 1: - result = send_oscam_reader(vars, ¶ms, 0); - break; - case 2: - result = send_oscam_entitlement(vars, ¶ms, 0); - break; - case 3: - result = send_oscam_status(vars, ¶ms, 0); - break; - case 4: - result = send_oscam_user_config(vars, ¶ms, 0); - break; - case 5: - result = send_oscam_reader_config(vars, ¶ms); - break; - case 6: - result = send_oscam_services(vars, ¶ms); - break; - case 7: - result = send_oscam_user_config_edit(vars, ¶ms, 0); - break; - //case 8: css file - case 9: - result = send_oscam_services_edit(vars, ¶ms); - break; - case 10: - result = send_oscam_savetpls(vars); - break; - case 11: - result = send_oscam_shutdown(vars, f, ¶ms, 0, keepalive, extraheader); - break; - case 12: - result = send_oscam_script(vars, ¶ms); - break; - case 13: - result = send_oscam_scanusb(vars); - break; - case 14: - result = send_oscam_files(vars, ¶ms, 0); - break; - case 15: - result = send_oscam_reader_stats(vars, ¶ms, 0); - break; - case 16: - result = send_oscam_failban(vars, ¶ms, 0); - break; - //case 17: js file - case 18: - result = send_oscam_api(vars, f, ¶ms, keepalive, 1, extraheader); - break; //oscamapi.html - case 19: - result = send_oscam_image(vars, f, ¶ms, NULL, modifiedheader, etagheader, extraheader); - break; - case 20: - result = send_oscam_image(vars, f, ¶ms, "ICMAI", modifiedheader, etagheader, extraheader); - break; - case 21: - result = send_oscam_graph(vars); - break; - case 22: - result = send_oscam_api(vars, f, ¶ms, keepalive, 1, extraheader); - break; //oscamapi.xml -#ifdef CS_CACHEEX - case 23: - result = send_oscam_cacheex(vars, ¶ms, 0); - break; -#endif - case 24: - result = send_oscam_api(vars, f, ¶ms, keepalive, 2, extraheader); - break; //oscamapi.json - case 25: - result = send_oscam_EMM(vars, ¶ms); - break; //emm.html - case 26: - result = send_oscam_EMM_running(vars, ¶ms); - break; //emm_running.html - case 27: - result = send_oscam_robots_txt(f); - break; //robots.txt -#ifdef MODULE_GHTTP - case 28: - result = send_oscam_ghttp(vars, ¶ms, 0); - break; -#endif -#ifdef WEBIF_LIVELOG - case 29: - result = send_oscam_logpoll(vars, ¶ms); - break; - //case 30: jquery.js -#endif -#ifdef WEBIF_WIKI - case 31: - result = send_oscam_wiki(vars, ¶ms); - break; - case 32: - result = send_oscam_wiki_status(vars, ¶ms); - break; -#endif - default: - result = send_oscam_status(vars, ¶ms, 0); - break; - } - if(pgidx != 19 && pgidx != 20 && pgidx != 21 && pgidx != 27) { cs_writeunlock(__func__, &http_lock); } - - if(result == NULL || !strcmp(result, "0") || cs_strlen(result) == 0) { send_error500(f); } - else if(strcmp(result, "1")) - { - //it doesn't make sense to check for modified etagheader here as standard template has timestamp in output and so site changes on every request - if(pgidx == 18) - { send_headers(f, 200, "OK", extraheader, "text/xml", 0, cs_strlen(result), NULL, 0); } - else if(pgidx == 21) - { send_headers(f, 200, "OK", extraheader, "image/svg+xml", 0, cs_strlen(result), NULL, 0); } - else if(pgidx == 24) - { send_headers(f, 200, "OK", extraheader, "text/javascript", 0, cs_strlen(result), NULL, 0); } -#ifdef WEBIF_WIKI - else if(pgidx == 31) - { send_headers(f, 200, "OK", extraheader, "application/json", 0, cs_strlen(result), NULL, 0); } -#endif - else - { send_headers(f, 200, "OK", extraheader, "text/html", 0, cs_strlen(result), NULL, 0); } - webif_write(result, f); - } - tpl_clear(vars); - } - NULLFREE(filebuf); - } - while(*keepalive == 1 && !exit_oscam); - return 0; -} - -static void *serve_process(void *conn) -{ - struct s_connection *myconn = (struct s_connection *)conn; - int32_t s = myconn->socket; - struct s_client *cl = myconn->cl; - IN_ADDR_T in; - IP_ASSIGN(in, myconn->remote); - - set_thread_name(__func__); - -#ifdef WITH_SSL - SSL *ssl = myconn->ssl; - SAFE_SETSPECIFIC(getssl, ssl); -#endif - NULLFREE(myconn); - - SAFE_SETSPECIFIC(getip, &in); - SAFE_SETSPECIFIC(getclient, cl); - - int8_t keepalive = 0; - SAFE_SETSPECIFIC(getkeepalive, &keepalive); - -#ifdef WITH_SSL - if(ssl_active) - { - if(SSL_set_fd(ssl, s)) - { - int32_t ok = (SSL_accept(ssl) != -1); - if(!ok) - { - int8_t tries = 100; - while(!ok && tries--) - { - int32_t err = SSL_get_error(ssl, -1); - if(err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) - { break; } - else - { - struct pollfd pfd; - pfd.fd = s; - pfd.events = POLLIN | POLLPRI; - int32_t rc = poll(&pfd, 1, -1); - if(rc < 0) - { - if(errno == EINTR || errno == EAGAIN) { continue; } - break; - } - if(rc == 1) - { ok = (SSL_accept(ssl) != -1); } - } - } - } - if(ok) - { - process_request((FILE *)ssl, in); - } - else - { - FILE *f; - f = fdopen(s, "r+"); - if(f != NULL) - { - char *ptr, *filebuf = NULL, *host = NULL; - int32_t bufsize = readRequest(f, in, &filebuf, 1); - - if(filebuf) - { - filebuf[bufsize] = '\0'; - host = strstr(filebuf, "Host: "); - if(host) - { - host += 6; - ptr = strchr(host, '\r'); - if(ptr) { ptr[0] = '\0'; } - } - } - if(host) - { - char extra[cs_strlen(host) + 20]; - snprintf(extra, sizeof(extra), "Location: https://%s", host); - send_error(f, 301, "Moved Permanently", extra, "This web server is running in SSL mode.", 1); - } - else - { send_error(f, 200, "Bad Request", NULL, "This web server is running in SSL mode.", 1); } - fflush(f); - fclose(f); - NULLFREE(filebuf); - } - else - { - cs_log_dbg(D_TRACE, "WebIf: fdopen(%d) failed. (errno=%d %s)", s, errno, strerror(errno)); - } - } - } - else { cs_log("WebIf: Error calling SSL_set_fd()."); } - SSL_shutdown(ssl); - close(s); - SSL_free(ssl); - } - else -#endif - { - FILE *f; - f = fdopen(s, "r+"); - if(f != NULL) - { - process_request(f, in); - fflush(f); - fclose(f); - } - else - { - cs_log_dbg(D_TRACE, "WebIf: fdopen(%d) failed. (errno=%d %s)", s, errno, strerror(errno)); - } - shutdown(s, SHUT_WR); - close(s); - } - - return NULL; -} - -/* Creates a random string with specified length. Note that dst must be one larger than size to hold the trailing \0*/ -static void create_rand_str(char *dst, int32_t size) -{ - int32_t i; - for(i = 0; i < size; ++i) - { - dst[i] = (rand() % 94) + 32; - } - dst[i] = '\0'; -} - -static void *http_server(void *UNUSED(d)) -{ - struct s_client *cl = create_client(first_client->ip); - if(cl == NULL) { return NULL; } - SAFE_SETSPECIFIC(getclient, cl); - cl->typ = 'h'; - int32_t s, reuse = 1; - struct s_connection *conn; - - set_thread_name(__func__); - - /* Create random string for nonce value generation */ - create_rand_str(noncekey, 32); - - /* Prepare base64 decoding array */ - b64prepare(); - webif_tpls_prepare(); -#ifdef WEBIF_WIKI - webif_wiki_prepare(); -#endif - - tpl_checkDiskRevisions(); - - cs_lock_create(__func__, &http_lock, "http_lock", 10000); - init_noncelocks(); - - memset(&p_stat_cur, 0x0, sizeof(p_stat_cur)); - - if(pthread_key_create(&getip, NULL)) - { - cs_log("Could not create getip"); - return NULL; - } - if(pthread_key_create(&getkeepalive, NULL)) - { - cs_log("Could not create getkeepalive"); - return NULL; - } - - struct SOCKADDR sin; - socklen_t len = 0; - memset(&sin, 0, sizeof(sin)); - - bool do_ipv6 = config_enabled(IPV6SUPPORT); -#ifdef IPV6SUPPORT - if(do_ipv6) - { - len = sizeof(struct sockaddr_in6); - if((sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) < 0) - { - cs_log("HTTP Server: ERROR: Creating IPv6 socket failed! (errno=%d %s)", errno, strerror(errno)); - cs_log("HTTP Server: Falling back to IPv4."); - do_ipv6 = false; - } - else if (IP_ISSET(cfg.http_srvip) && (IN6_IS_ADDR_V4MAPPED(&cfg.http_srvip) || IN6_IS_ADDR_V4COMPAT(&cfg.http_srvip))) // ipv4 set as http_srvip - { - do_ipv6 = false; - } - else - { - struct sockaddr_in6 *ia = (struct sockaddr_in6 *)&sin; - - if (IP_ISSET(cfg.http_srvip)) - { - IP_ASSIGN(SIN_GET_ADDR(sin), cfg.http_srvip); - } - else if (IP_ISSET(cfg.srvip)) - { - IP_ASSIGN(SIN_GET_ADDR(sin), cfg.srvip); - } - else - { - ia->sin6_addr = in6addr_any; - } - - ia->sin6_family = AF_INET6; - ia->sin6_port = htons(cfg.http_port); - } - } -#endif - if(!do_ipv6) - { - len = sizeof(struct sockaddr_in); - if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) - { - cs_log("HTTP Server: ERROR: Creating socket failed! (errno=%d %s)", errno, strerror(errno)); - return NULL; - } - SIN_GET_FAMILY(sin) = AF_INET; - if(IP_ISSET(cfg.http_srvip)) - { IP_ASSIGN(SIN_GET_ADDR(sin), cfg.http_srvip); } - else if(IP_ISSET(cfg.srvip)) - { IP_ASSIGN(SIN_GET_ADDR(sin), cfg.srvip); } - // The default is INADDR_ANY (0) - SIN_GET_PORT(sin) = htons(cfg.http_port); - } - - if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) - { - cs_log("HTTP Server: Setting SO_REUSEADDR via setsockopt failed! (errno=%d %s)", errno, strerror(errno)); - } - - if(bind(sock, (struct sockaddr *)&sin, len) < 0) - { - cs_log("HTTP Server couldn't bind on port %d (errno=%d %s). Not starting HTTP!", cfg.http_port, errno, strerror(errno)); - close(sock); - return NULL; - } - - if(listen(sock, SOMAXCONN) < 0) - { - cs_log("HTTP Server: Call to listen() failed! (errno=%d %s)", errno, strerror(errno)); - close(sock); - return NULL; - } - -#ifdef WITH_SSL - if(pthread_key_create(&getssl, NULL)) - { - cs_log("Could not create getssl"); - } - - SSL_CTX *ctx = NULL; - if(cfg.http_use_ssl) - { - ctx = SSL_Webif_Init(); - if(ctx == NULL) - { cs_log("SSL could not be initialized. Starting WebIf in plain mode."); } - else { ssl_active = 1; } - } - else { ssl_active = 0; } - cs_log("HTTP%s Server running. ip=%s port=%d (%s)", ssl_active ? "S" : "", cs_inet_ntoa(SIN_GET_ADDR(sin)), cfg.http_port, ssl_active ? OPENSSL_VERSION_TEXT : "no SSL"); -#else - cs_log("HTTP Server running. ip=%s port=%d", cs_inet_ntoa(SIN_GET_ADDR(sin)), cfg.http_port); -#endif - - struct SOCKADDR remote; - memset(&remote, 0, sizeof(remote)); - - while(!exit_oscam) - { - if((s = accept(sock, (struct sockaddr *) &remote, &len)) < 0) - { - if(exit_oscam) - { break; } - if(errno != EAGAIN && errno != EINTR) - { - cs_log("HTTP Server: Error calling accept() (errno=%d %s)", errno, strerror(errno)); - cs_sleepms(100); - } - else { cs_sleepms(5); } - continue; - } - else - { - getpeername(s, (struct sockaddr *) &remote, &len); - if(!cs_malloc(&conn, sizeof(struct s_connection))) - { - close(s); - continue; - } - setTCPTimeouts(s); - cur_client()->last = time((time_t *)0); //reset last busy time - conn->cl = cur_client(); -#ifdef IPV6SUPPORT - if(do_ipv6) - { - struct sockaddr_in6 *ra = (struct sockaddr_in6 *)&remote; - memcpy(&conn->remote, &ra->sin6_addr, sizeof(struct in6_addr)); - } - else - { - struct sockaddr_in *fba = (struct sockaddr_in *)&remote; - struct in6_addr taddr; - memset(&taddr, 0, sizeof(taddr)); - taddr.s6_addr32[3] = fba->sin_addr.s_addr; - memcpy(&conn->remote, &taddr, sizeof(struct in6_addr)); - } -#else - memcpy(&conn->remote, &remote.sin_addr, sizeof(struct in_addr)); -#endif - conn->socket = s; -#ifdef WITH_SSL - conn->ssl = NULL; - if(ssl_active) - { - conn->ssl = SSL_new(ctx); - if(conn->ssl == NULL) - { - close(s); - cs_log("WebIf: Error calling SSL_new()."); - continue; - } - } -#endif - - int32_t ret = start_thread("webif workthread", serve_process, (void *)conn, NULL, 1, 1); - if(ret) - { - NULLFREE(conn); - } - } - } - // Wait a bit so that we don't close ressources while http threads are active - cs_sleepms(300); -#ifdef WITH_SSL - SSL_CTX_free(ctx); - CRYPTO_set_dynlock_create_callback(NULL); - CRYPTO_set_dynlock_lock_callback(NULL); - CRYPTO_set_dynlock_destroy_callback(NULL); - CRYPTO_set_locking_callback(NULL); - CRYPTO_set_id_callback(NULL); - OPENSSL_free(lock_cs); - lock_cs = NULL; -#endif - cs_log("HTTP Server stopped"); - free_client(cl); - close(sock); - return NULL; -} - -void webif_client_reset_lastresponsetime(struct s_client * cl) -{ - int32_t i; - for(i = 0; i < CS_ECM_RINGBUFFER_MAX; i++) - { - cl->cwlastresptimes[i].duration = 0; - cl->cwlastresptimes[i].timestamp = time((time_t *)0); - cl->cwlastresptimes[i].rc = 0; - } - cl->cwlastresptimes_last = 0; -} - -void webif_client_add_lastresponsetime(struct s_client * cl, int32_t ltime, time_t timestamp, int32_t rc) -{ - int32_t last = cl->cwlastresptimes_last = (cl->cwlastresptimes_last + 1) & (CS_ECM_RINGBUFFER_MAX - 1); - cl->cwlastresptimes[last].duration = ltime > 9999 ? 9999 : ltime; - cl->cwlastresptimes[last].timestamp = timestamp; - cl->cwlastresptimes[last].rc = rc; -} - -void webif_client_init_lastreader(struct s_client * client, ECM_REQUEST * er, struct s_reader * er_reader, const char *stxt[]) -{ - if(er_reader) - { - if(er->rc == E_FOUND) - { cs_strncpy(client->lastreader, er_reader->label, sizeof(client->lastreader)); } - else if(er->rc == E_CACHEEX) - #ifdef CS_CACHEEX_AIO - { - if (cfg.cacheex_srcname_webif) - { - cs_strncpy(client->lastreader, username(er_reader->client), sizeof(client->lastreader)); - } - else - { - cs_strncpy(client->lastreader, "cache3", sizeof(client->lastreader)); - } - } - #else - { cs_strncpy(client->lastreader, "cache3", sizeof(client->lastreader)); } - #endif - else if(er->rc < E_NOTFOUND) - { snprintf(client->lastreader, sizeof(client->lastreader) - 1, "%.54s (cache)", er_reader->label); } - else - { cs_strncpy(client->lastreader, stxt[er->rc], sizeof(client->lastreader)); } - } - else - { - cs_strncpy(client->lastreader, stxt[er->rc], sizeof(client->lastreader)); - } -} - -void webif_init(void) -{ - char buf[8], fname[256]; - snprintf(buf, 8, "%'d", 7); - if(strcmp(buf, "7")) - { - useLocal = 0; - } - - if(cfg.http_port == 0) - { - cs_log("http disabled"); - return; - } - - get_config_filename(fname, sizeof(fname), "oscam.srvid2"); - use_srvid2 = file_exists(fname); - - if(start_thread("http", http_server, NULL, &httpthread, 0, 1) == 0) - { - httpthread_running = 1; - } -} - -void webif_close(void) -{ - if(!sock) - { return; } - - shutdown(sock, 2); - close(sock); - - if(httpthread_running) - { SAFE_THREAD_JOIN(httpthread, NULL); } -} - -#endif diff --git a/module-webif.h b/module-webif.h old mode 100644 new mode 100755 diff --git a/modules.h b/modules.h old mode 100644 new mode 100755 diff --git a/oscam-aes.c b/oscam-aes.c old mode 100644 new mode 100755 diff --git a/oscam-aes.h b/oscam-aes.h old mode 100644 new mode 100755 diff --git a/oscam-array.c b/oscam-array.c old mode 100644 new mode 100755 diff --git a/oscam-array.h b/oscam-array.h old mode 100644 new mode 100755 diff --git a/oscam-cache.c b/oscam-cache.c old mode 100644 new mode 100755 diff --git a/oscam-cache.c.bak b/oscam-cache.c.bak old mode 100644 new mode 100755 diff --git a/oscam-cache.h b/oscam-cache.h old mode 100644 new mode 100755 diff --git a/oscam-chk.c b/oscam-chk.c old mode 100644 new mode 100755 diff --git a/oscam-chk.c.bak b/oscam-chk.c.bak old mode 100644 new mode 100755 diff --git a/oscam-chk.c.orig b/oscam-chk.c.orig deleted file mode 100755 index 3dd9536..0000000 --- a/oscam-chk.c.orig +++ /dev/null @@ -1,1316 +0,0 @@ -#define MODULE_LOG_PREFIX "chk" - -#include "globals.h" -#include "oscam-cache.h" -#include "oscam-chk.h" -#include "oscam-ecm.h" -#include "oscam-client.h" -#include "oscam-lock.h" -#include "oscam-net.h" -#include "oscam-string.h" -#include "module-stat.h" -#include "oscam-reader.h" - -#define CS_NANO_CLASS 0xE2 -#define OK 1 -#define ERROR 0 - -uint32_t get_fallbacktimeout(uint16_t caid) -{ - uint32_t ftimeout = caidvaluetab_get_value(&cfg.ftimeouttab, caid, 0); - - if(ftimeout == 0) { ftimeout = cfg.ftimeout; } - - if(ftimeout < 100) { ftimeout = CS_CLIENT_TIMEOUT / 2; } - if(ftimeout >= cfg.ctimeout) { ftimeout = cfg.ctimeout - 100; } - - return ftimeout; -} - -static int32_t find_nano(uint8_t *ecm, int32_t l, uint8_t nano, int32_t s) -{ - uint8_t *snano; - - if(s >= l) { return 0; } - if(!s) { s = (ecm[4] == 0xD2) ? 12 : 9; } // tpsflag -> offset+3 - snano = ecm + s; - - while((*snano != nano) && (s < l)) - { - if(*snano == 0xEA) { return 0; } - snano++; - s++; - } - - return (s < l) ? ++s : 0; -} - -static int32_t chk_class(ECM_REQUEST *er, CLASSTAB *clstab, const char *type, const char *name) -{ - int32_t i, j, an, cl_n, l; - uint8_t ecm_class; - - if(er->caid != 0x0500 && er->caid != 0x4AE1) { return 1; } - if(!clstab->bn && !clstab->an) { return 1; } - - j = an = cl_n = 0; - - if(er->caid == 0x0500) - { - while((j = find_nano(er->ecm, er->ecmlen, CS_NANO_CLASS, j)) > 0) - { - l = er->ecm[j]; - if(l + j > er->ecmlen) { continue; } // skip, this is not a valid class identifier! - - ecm_class = er->ecm[j + l]; - cs_log_dbg(D_CLIENT, "ecm class=%02X", ecm_class); - - for(i = 0; i < clstab->bn; i++) // search in blocked - { - if(ecm_class == clstab->bclass[i]) - { - cs_log_dbg(D_CLIENT, "class %02X rejected by %s '%s' !%02X filter", - ecm_class, type, name, ecm_class); - return 0; - } - } - cl_n++; - - for(i = 0; i < clstab->an; i++) // search in allowed - { - if(ecm_class == clstab->aclass[i]) - { - an++; - break; - } - } - j += l; - } - } - else - { - if(er->prid != 0x11 || er->ecm[0] == 0) { return 1; } - - cl_n++; - ecm_class = er->ecm[5]; - cs_log_dbg(D_CLIENT, "ecm class=%02X", ecm_class); - - for(i = 0; i < clstab->bn; i++) // search in blocked - { - if(ecm_class == clstab->bclass[i]) - { - cs_log_dbg(D_CLIENT, "class %02X rejected by %s '%s' !%02X filter", - ecm_class, type, name, ecm_class); - return 0; - } - } - - for(i = 0; i < clstab->an; i++) // search in allowed - { - if(ecm_class == clstab->aclass[i]) - { - an++; - break; - } - } - } - - if(cl_n && clstab->an) - { - if(an) - { cs_log_dbg(D_CLIENT, "ECM classes allowed by %s '%s' filter", type, name); } - else - { - cs_log_dbg(D_CLIENT, "ECM classes don't match %s '%s' filter, rejecting", type, name); - return 0; - } - } - - return 1; -} - -int32_t chk_srvid_match(ECM_REQUEST *er, SIDTAB *sidtab) -{ - int32_t i, rc = 0; - - if(!sidtab->num_caid) - { rc |= 1; } - else - for(i = 0; (i < sidtab->num_caid) && (!(rc & 1)); i++) - if(er->caid == sidtab->caid[i]) { rc |= 1; } - - if(!er->prid || !sidtab->num_provid) - { rc |= 2; } - else - for(i = 0; (i < sidtab->num_provid) && (!(rc & 2)); i++) - if(er->prid == sidtab->provid[i]) { rc |= 2; } - - if(!sidtab->num_srvid) - { rc |= 4; } - else - for(i = 0; (i < sidtab->num_srvid) && (!(rc & 4)); i++) - if(er->srvid == sidtab->srvid[i]) { rc |= 4; } - - return (rc == 7); -} - -#ifdef CS_CACHEEX_AIO -int32_t chk_srvid_disablecrccws_only_for_exception(ECM_REQUEST *er) -{ - int32_t nr; - SIDTAB *sidtab; - - for(nr = 0, sidtab = cfg.sidtab; sidtab; sidtab = sidtab->next, nr++) - { - if(sidtab->disablecrccws_only_for_exception && (sidtab->num_caid | sidtab->num_provid | sidtab->num_srvid) && chk_srvid_match(er, sidtab)) - { - return(1); - } - } - return(0); -} - -int32_t chk_srvid_no_wait_time(ECM_REQUEST *er) -{ - int32_t nr; - SIDTAB *sidtab; - - for(nr = 0, sidtab = cfg.sidtab; sidtab; sidtab = sidtab->next, nr++) - { - if(sidtab->no_wait_time && (sidtab->num_caid | sidtab->num_provid | sidtab->num_srvid) && chk_srvid_match(er, sidtab)) - { - return(1); - } - } - return(0); -} - -int32_t chk_srvid_localgenerated_only_exception(ECM_REQUEST *er) -{ - int32_t nr; - SIDTAB *sidtab; - - for(nr = 0, sidtab = cfg.sidtab; sidtab; sidtab = sidtab->next, nr++) - { - if(sidtab->lg_only_exception && (sidtab->num_caid | sidtab->num_provid | sidtab->num_srvid) && chk_srvid_match(er, sidtab)) - { - return(1); - } - } - return(0); -} -#endif - -int32_t chk_srvid(struct s_client *cl, ECM_REQUEST *er) -{ - int32_t nr, rc = 0; - SIDTAB *sidtab; - - if(!cl->sidtabs.ok) - { - if(!cl->sidtabs.no) { return (1); } - rc = 1; - } - - for(nr = 0, sidtab = cfg.sidtab; sidtab; sidtab = sidtab->next, nr++) - { - if(sidtab->num_caid | sidtab->num_provid | sidtab->num_srvid) - { - if((cl->sidtabs.no & ((SIDTABBITS)1 << nr)) && (chk_srvid_match(er, sidtab))) - { return (0); } - - if((cl->sidtabs.ok & ((SIDTABBITS)1 << nr)) && (chk_srvid_match(er, sidtab))) - { rc = 1; } - } - } - return (rc); -} - -int32_t has_srvid(struct s_client *cl, ECM_REQUEST *er) -{ - if(!cl->sidtabs.ok) - { return 0; } - - int32_t nr; - SIDTAB *sidtab; - - for(nr = 0, sidtab = cfg.sidtab; sidtab; sidtab = sidtab->next, nr++) - { - if(sidtab->num_srvid) - { - if((cl->sidtabs.ok & ((SIDTABBITS)1 << nr)) && (chk_srvid_match(er, sidtab))) - { return 1; } - } - } - return 0; -} - -int32_t has_lb_srvid(struct s_client *cl, ECM_REQUEST *er) -{ - if(!cl->lb_sidtabs.ok) - { return 0; } - - int32_t nr; - SIDTAB *sidtab; - - for(nr = 0, sidtab = cfg.sidtab; sidtab; sidtab = sidtab->next, nr++) - { - if((cl->lb_sidtabs.ok & ((SIDTABBITS)1 << nr)) && (chk_srvid_match(er, sidtab))) - { return 1; } - } - return 0; -} - -int32_t chk_srvid_match_by_caid_prov(uint16_t caid, uint32_t provid, SIDTAB *sidtab) -{ - int32_t i, rc = 0; - - if(!sidtab->num_caid) - { rc |= 1; } - else - for(i = 0; (i < sidtab->num_caid) && (!(rc & 1)); i++) - if(caid == sidtab->caid[i]) { rc |= 1; } - - if(!sidtab->num_provid) - { rc |= 2; } - else - for(i = 0; (i < sidtab->num_provid) && (!(rc & 2)); i++) - if(provid == sidtab->provid[i]) { rc |= 2; } - - return (rc == 3); -} - -int32_t chk_srvid_by_caid_prov(struct s_client *cl, uint16_t caid, uint32_t provid) -{ - int32_t nr, rc = 0; - SIDTAB *sidtab; - - if(!cl->sidtabs.ok) - { - if(!cl->sidtabs.no) { return (1); } - rc = 1; - } - - for(nr = 0, sidtab = cfg.sidtab; sidtab; sidtab = sidtab->next, nr++) - { - if(sidtab->num_caid | sidtab->num_provid) - { - if((cl->sidtabs.no & ((SIDTABBITS)1 << nr)) && !sidtab->num_srvid && - (chk_srvid_match_by_caid_prov(caid, provid, sidtab))) - { return (0); } - - if((cl->sidtabs.ok & ((SIDTABBITS)1 << nr)) && - (chk_srvid_match_by_caid_prov(caid, provid, sidtab))) - { rc = 1; } - } - } - return (rc); -} - -int32_t chk_srvid_by_caid_prov_rdr(struct s_reader *rdr, uint16_t caid, uint32_t provid) -{ - int32_t nr, rc = 0; - SIDTAB *sidtab; - - if(!rdr->sidtabs.ok) - { - if(!rdr->sidtabs.no) { return (1); } - rc = 1; - } - - for(nr = 0, sidtab = cfg.sidtab; sidtab; sidtab = sidtab->next, nr++) - { - if(sidtab->num_caid | sidtab->num_provid) - { - if((rdr->sidtabs.no & ((SIDTABBITS)1 << nr)) && !sidtab->num_srvid && - (chk_srvid_match_by_caid_prov(caid, provid, sidtab))) - { return (0); } - - if((rdr->sidtabs.ok & ((SIDTABBITS)1 << nr)) && - (chk_srvid_match_by_caid_prov(caid, provid, sidtab))) - { rc = 1; } - } - } - return (rc); -} - -int32_t chk_is_betatunnel_caid(uint16_t caid) -{ - if(caid == 0x1702 || caid == 0x1722) { return 1; } - if(caid == 0x1801 || caid == 0x1833 || caid == 0x1834 || caid == 0x1835) { return 2; } - return 0; -} - -uint16_t chk_on_btun(uint8_t chk_sx, struct s_client *cl, ECM_REQUEST *er) -{ - if(chk_is_betatunnel_caid(er->caid)) - { - int32_t i; - TUNTAB *ttab; - ttab = &cl->ttab; - - if(ttab->ttdata) - { - for(i = 0; i < ttab->ttnum; i++) - { - if(er->caid == ttab->ttdata[i].bt_caidfrom) - { - if(er->srvid == ttab->ttdata[i].bt_srvid) { return ttab->ttdata[i].bt_caidto; } - if(chk_sx && ttab->ttdata[i].bt_srvid == 0xFFFF) { return ttab->ttdata[i].bt_caidto; } - if(!chk_sx && !ttab->ttdata[i].bt_srvid) { return ttab->ttdata[i].bt_caidto; } - } - } - } - - if(chk_sx) - return lb_get_betatunnel_caid_to(er); - } - return 0; -} - -// server filter for newcamd -int32_t chk_sfilter(ECM_REQUEST *er, PTAB *ptab) -{ -#ifdef MODULE_NEWCAMD - int32_t i, j, pi, rc = 1; - uint16_t caid, scaid; - uint32_t prid, sprid; - - if(!ptab) { return (1); } - struct s_client *cur_cl = cur_client(); - - caid = er->caid; - prid = er->prid; - pi = cur_cl->port_idx; - - if(cfg.ncd_mgclient) - { return 1; } - - if(ptab->nports && ptab->ports[pi].ncd && ptab->ports[pi].ncd->ncd_ftab.nfilts) - { - for(rc = j = 0; (!rc) && (j < ptab->ports[pi].ncd->ncd_ftab.nfilts); j++) - { - scaid = ptab->ports[pi].ncd->ncd_ftab.filts[j].caid; - if(caid == 0 || (caid != 0 && caid == scaid)) - { - for(i = 0; (!rc) && i < ptab->ports[pi].ncd->ncd_ftab.filts[j].nprids; i++) - { - sprid = ptab->ports[pi].ncd->ncd_ftab.filts[j].prids[i]; - cs_log_dbg(D_CLIENT, "trying server filter %04X@%06X", scaid, sprid); - if(prid == sprid) - { - rc = 1; - cs_log_dbg(D_CLIENT, "%04X@%06X allowed by server filter %04X@%06X", - caid, prid, scaid, sprid); - } - } - } - } - - if(!rc) - { - cs_log_dbg(D_CLIENT, "no match, %04X@%06X rejected by server filters", caid, prid); - snprintf(er->msglog, MSGLOGSIZE, "no server match %04X@%06X", caid, (uint32_t) prid); - - if(!er->rcEx) { er->rcEx = (E1_LSERVER << 4) | E2_IDENT; } - return (rc); - } - } - return (rc); -#else - (void)er; - (void)ptab; - return 1; -#endif -} - -static int32_t chk_chid(ECM_REQUEST *er, FTAB *fchid, char *type, char *name) -{ - int32_t rc = 1, i, j, found_caid = 0; - if(!fchid->nfilts) { return 1; } - if(er->chid == 0 && er->ecm[0] == 0) { return 1; } // skip empty ecm, chid 00 to avoid no matching readers in dvbapi - - for(i = rc = 0; (!rc) && i < fchid->nfilts; i++) - { - if(er->caid == fchid->filts[i].caid) - { - found_caid = 1; - for(j = 0; (!rc) && j < fchid->filts[i].nprids; j++) - { - cs_log_dbg(D_CLIENT, "trying %s '%s' CHID filter %04X:%04X", - type, name, fchid->filts[i].caid, fchid->filts[i].prids[j]); - - if(er->chid == fchid->filts[i].prids[j]) - { - cs_log_dbg(D_CLIENT, "%04X:%04X allowed by %s '%s' CHID filter %04X:%04X", - er->caid, er->chid, type, name, fchid->filts[i].caid, fchid->filts[i].prids[j]); - rc = 1; - } - } - } - } - - if(!rc) - { - if(found_caid) - cs_log_dbg(D_CLIENT, "no match, %04X:%04X rejected by %s '%s' CHID filter(s)", - er->caid, er->chid, type, name); - else - { - rc = 1; - cs_log_dbg(D_CLIENT, "%04X:%04X allowed by %s '%s' CHID filter, CAID not spezified", - er->caid, er->chid, type, name); - } - } - return (rc); -} - -int32_t chk_ident_filter(uint16_t rcaid, uint32_t rprid, FTAB *ftab) -{ - int32_t i, j, rc = 1; - uint16_t caid = 0; - uint32_t prid = 0; - - if(ftab->nfilts) - { - for(rc = i = 0; (!rc) && (i < ftab->nfilts); i++) - { - caid = ftab->filts[i].caid; - if((caid != 0 && caid == rcaid) || caid == 0) - { - for(j = 0; (!rc) && (j < ftab->filts[i].nprids); j++) - { - prid = ftab->filts[i].prids[j]; - if(prid == rprid) - { - rc=1; - } - } - } - } - - if(!rc) - { return 0; } - } - - return(rc); -} - -int32_t chk_ufilters(ECM_REQUEST *er) -{ - int32_t i, j, rc = 1; - uint16_t ucaid; - uint32_t uprid; - struct s_client *cur_cl = cur_client(); - - if(cur_cl->ftab.nfilts) - { - FTAB *f = &cur_cl->ftab; - for(i = rc = 0; (!rc) && (i < f->nfilts); i++) - { - ucaid = f->filts[i].caid; - if(er->caid == 0 || ucaid == 0 || (er->caid != 0 && er->caid == ucaid)) - { - if (er->prid == 0) - { - cs_log_dbg(D_CLIENT, "%04X@%06X allowed by user '%s' filter caid %04X prid %06X", - er->caid, er->prid, cur_cl->account->usr, ucaid, 0); - rc = 1; - break; - } - - for(j = rc = 0; (!rc) && (j < f->filts[i].nprids); j++) - { - uprid = f->filts[i].prids[j]; - cs_log_dbg(D_CLIENT, "trying user '%s' filter %04X@%06X", cur_cl->account->usr, ucaid, uprid); - - if(er->prid == uprid) - { - rc = 1; - cs_log_dbg(D_CLIENT, "%04X@%06X allowed by user '%s' filter %04X@%06X", - er->caid, er->prid, cur_cl->account->usr, ucaid, uprid); - } - } - } - } - - if(!rc) - { - cs_log_dbg(D_CLIENT, "no match, %04X@%06X rejected by user '%s' filters", - er->caid, er->prid, cur_cl->account->usr); - - snprintf(er->msglog, MSGLOGSIZE, "no card support %04X@%06X", er->caid, (uint32_t) er->prid); - - if(!er->rcEx) { er->rcEx = (E1_USER << 4) | E2_IDENT; } - return (rc); - } - } - - if(!(rc = chk_class(er, &cur_cl->cltab, "user", cur_cl->account->usr))) - { - if(!er->rcEx) { er->rcEx = (E1_USER << 4) | E2_CLASS; } - } - else if(!(rc = chk_chid(er, &cur_cl->fchid, "user", cur_cl->account->usr))) - { - if(!er->rcEx) { er->rcEx = (E1_USER << 4) | E2_CHID; } - } - - if(rc) { er->rcEx = 0; } - - return (rc); -} - -int32_t chk_rsfilter(struct s_reader *reader, ECM_REQUEST *er) -{ - int32_t i, rc = 1; - uint16_t caid; - uint32_t prid; - - if(reader->ncd_disable_server_filt) - { - cs_log_dbg(D_CLIENT, "%04X@%06X allowed - server filters disabled", er->caid, er->prid); - return 1; - } - - rc = 0; - caid = reader->caid; - if(caid == er->caid) - { - for(i = 0; (!rc) && (i < reader->nprov); i++) - { - prid = (uint32_t)((reader->prid[i][1] << 16) | (reader->prid[i][2] << 8) | (reader->prid[i][3])); - cs_log_dbg(D_CLIENT, "trying server '%s' filter %04X@%06X", reader->device, caid, prid); - - if(prid == er->prid || !er->prid) - { - rc = 1; - cs_log_dbg(D_CLIENT, "%04X@%06X allowed by server '%s' filter %04X@%06X", - er->caid, er->prid, reader->device, caid, prid); - } - } - } - - if(!rc) - { - cs_log_dbg(D_CLIENT, "no match, %04X@%06X rejected by server '%s' filters", - er->caid, er->prid, reader->device); - - if(!er->rcEx) { er->rcEx = (E1_SERVER << 4) | E2_IDENT; } - return 0; - } - - return (rc); -} - -int32_t chk_rfilter2(uint16_t rcaid, uint32_t rprid, struct s_reader *rdr) -{ - int32_t i, j, rc = 1; - uint16_t caid = 0; - uint32_t prid = 0; - - if(rdr->ftab.nfilts) - { - for(rc = i = 0; (!rc) && (i < rdr->ftab.nfilts); i++) - { - caid = rdr->ftab.filts[i].caid; - if((caid != 0 && caid == rcaid) || caid == 0) - { - for(j = 0; (!rc) && (j < rdr->ftab.filts[i].nprids); j++) - { - prid = rdr->ftab.filts[i].prids[j]; - cs_log_dbg(D_CLIENT, "trying reader '%s' filter %04X@%06X", rdr->label, caid, prid); - - if(prid == rprid) - { - rc = 1; - cs_log_dbg(D_CLIENT, "%04X@%06X allowed by reader '%s' filter %04X@%06X", - rcaid, rprid, rdr->label, caid, prid); - } - } - } - } - - if(!rc) - { - cs_log_dbg(D_CLIENT, "no match, %04X@%06X rejected by reader '%s' filters", - rcaid, rprid, rdr->label); - return 0; - } - } - - return (rc); -} - -static int32_t chk_rfilter(ECM_REQUEST *er, struct s_reader *rdr) -{ - return chk_rfilter2(er->caid, er->prid, rdr); -} - -int32_t chk_ctab(uint16_t caid, CAIDTAB *ctab) -{ - if(!caid || !ctab->ctnum) - { return 1; } - - int32_t i; - for(i = 0; i < ctab->ctnum; i++) - { - CAIDTAB_DATA *d = &ctab->ctdata[i]; - if(!d->caid) - { - return 0; - } - if((caid & d->mask) == d->caid) - { return 1; } - } - return 0; -} - -int32_t chk_ctab_ex(uint16_t caid, CAIDTAB *ctab) -{ - if(!caid || !ctab->ctnum) - { return 0; } - - int32_t i; - for(i = 0; i < ctab->ctnum; i++) - { - CAIDTAB_DATA *d = &ctab->ctdata[i]; - if(!d->caid) - { - return 0; - } - - if((caid & d->mask) == d->caid) - { - return 1; - } - } - return 0; -} - -uint8_t is_localreader(struct s_reader *rdr, ECM_REQUEST *er) // to be used for LB/reader selections checks only -{ - if(!rdr) return 0; - - if(!is_network_reader(rdr)) - { - return 1; - } - - if(!rdr->localcards.nfilts) { return 0; } - - int32_t i, k; - for(i = 0; i < rdr->localcards.nfilts; i++) - { - uint16_t tcaid = rdr->localcards.filts[i].caid; - if(tcaid && tcaid == er->caid) // caid match - { - int32_t nprids = rdr->localcards.filts[i].nprids; - if(!nprids) // No Provider -> Ok - { return 1; } - - for(k = 0; k < nprids; k++) - { - uint32_t prid = rdr->localcards.filts[i].prids[k]; - if(prid == er->prid) // Provider matches - { - return 1; - } - } - } - } - - return 0; -} - -uint8_t chk_is_fixed_fallback(struct s_reader *rdr, ECM_REQUEST *er) -{ - if(!rdr->fallback && !rdr->fallback_percaid.nfilts) { return 0; } - - if(!rdr->fallback_percaid.nfilts) - { - if(rdr->fallback) - { return 1; } - } - - int32_t i, k; - for(i = 0; i < rdr->fallback_percaid.nfilts; i++) - { - uint16_t tcaid = rdr->fallback_percaid.filts[i].caid; - if(tcaid && (tcaid == er->caid || (tcaid < 0x0100 && (er->caid >> 8) == tcaid))) // caid match - { - int32_t nprids = rdr->fallback_percaid.filts[i].nprids; - if(!nprids) // No Provider ->Ok - { return 1; } - - for(k = 0; k < nprids; k++) - { - uint32_t prid = rdr->fallback_percaid.filts[i].prids[k]; - if(prid == er->prid) // Provider matches - { - return 1; - } - } - } - } - - return 0; -} - -#ifdef CS_CACHEEX_AIO -uint8_t chk_lg_only(ECM_REQUEST *er, FTAB *lg_only_ftab) -{ - int32_t i, k; - - if(!lg_only_ftab->nfilts) - return 0; - - for(i = 0; i < lg_only_ftab->nfilts; i++) - { - uint16_t tcaid = lg_only_ftab->filts[i].caid; - if(tcaid && (tcaid == er->caid || (tcaid < 0x0100 && (er->caid >> 8) == tcaid))) // caid match - { - int32_t nprids = lg_only_ftab->filts[i].nprids; - if(!nprids) // No Provider ->Ok - { return 1; } - - for(k = 0; k < nprids; k++) - { - uint32_t prid = lg_only_ftab->filts[i].prids[k]; - if(prid == NO_PROVID_VALUE || prid == er->prid) // Provider matches - { - return 1; - } - } - } - } - - return 0; -} - -uint8_t chk_lg_only_cp(uint16_t caid, uint32_t prid, FTAB *lg_only_ftab) -{ - int32_t i, k; - - if(!lg_only_ftab->nfilts) - return 0; - - for(i = 0; i < lg_only_ftab->nfilts; i++) - { - uint16_t tcaid = lg_only_ftab->filts[i].caid; - if(tcaid && (tcaid == caid || (tcaid < 0x0100 && (caid >> 8) == tcaid))) // caid match - { - int32_t nprids = lg_only_ftab->filts[i].nprids; - if(!nprids) // No Provider ->Ok - { return 1; } - - for(k = 0; k < nprids; k++) - { - uint32_t fprid = lg_only_ftab->filts[i].prids[k]; - if(fprid == NO_PROVID_VALUE || fprid == prid) // Provider matches - { - return 1; - } - } - } - } - - return 0; -} -#endif - -uint8_t chk_has_fixed_fallback(ECM_REQUEST *er) -{ - struct s_ecm_answer *ea; - struct s_reader *rdr; - int32_t n_falb = 0; - for(ea = er->matching_rdr; ea; ea = ea->next) - { - rdr = ea->reader; - if(chk_is_fixed_fallback(rdr, er)) - { n_falb++; } - } - return n_falb; -} - -uint8_t chk_if_ignore_checksum(ECM_REQUEST *er, FTAB *disablecrc_only_for) -{ - if(!disablecrc_only_for->nfilts) { return 0; } - - int32_t i, k; - for(i = 0; i < disablecrc_only_for->nfilts; i++) - { - uint16_t tcaid = disablecrc_only_for->filts[i].caid; - if(tcaid && (tcaid == er->caid || (tcaid < 0x0100 && (er->caid >> 8) == tcaid))) // caid match - { - int32_t nprids = disablecrc_only_for->filts[i].nprids; - if(!nprids) // No Provider ->Ok - { return 1; } - - for(k = 0; k < nprids; k++) - { - uint32_t prid =disablecrc_only_for->filts[i].prids[k]; - if(prid == er->prid) // Provider matches - { return 1; } - } - } - } - - return 0; -} - -int32_t matching_reader(ECM_REQUEST *er, struct s_reader *rdr) -{ - // simple checks first: - if(!er || !rdr) - { return (0); } - - // reader active? - struct s_client *cl = rdr->client; - if(!cl || !rdr->enable) - { return (0); } - - // if physical reader a card needs to be inserted - if(!is_network_reader(rdr) && rdr->card_status != CARD_INSERTED) - { return (0); } - - // Checking connected & group valid: - struct s_client *cur_cl = er->client; //cur_client(); - -#ifdef CS_CACHEEX - // Cacheex=3 defines a Cacheex-only reader. never match them. - if(rdr->cacheex.mode == 3) - { return (0); } - if(rdr->cacheex.mode == 2 && !rdr->cacheex.allow_request) - { return (0); } -#endif - - if(!(rdr->grp & cur_cl->grp)) - { return (0); } - - // Checking caids: - if((!er->ocaid || !chk_ctab(er->ocaid, &rdr->ctab)) && !chk_ctab(er->caid, &rdr->ctab)) - { - cs_log_dbg(D_TRACE, "caid %04X not found in caidlist reader %s", er->caid, rdr->label); - return 0; - } - - if(!(rdr->typ == R_EMU) && !is_network_reader(rdr) && ((rdr->caid >> 8) != ((er->caid >> 8) & 0xFF) && (rdr->caid >> 8) != ((er->ocaid >> 8) & 0xFF))) - { - if (!rdr->csystem) - { return 0; } - - int i, caid_found = 0; - for(i = 0; rdr->csystem->caids[i]; i++) - { - uint16_t cs_caid = rdr->csystem->caids[i]; - if(!cs_caid) - { continue; } - - if(cs_caid == er->caid || cs_caid == er->ocaid) - { - caid_found = 1; - break; - } - } - - if(!caid_found) - { return 0; } - } - - // Supports long ecms? - if(er->ecmlen > 255 && is_network_reader(rdr) && !rdr->ph.large_ecm_support) - { - cs_log_dbg(D_TRACE, "no large ecm support (l=%d) for reader %s", er->ecmlen, rdr->label); - return 0; - } - - // Checking services: - if(!chk_srvid(rdr->client, er)) - { - cs_log_dbg(D_TRACE, "service %04X not matching reader %s", er->srvid, rdr->label); - return (0); - } - - // Checking ident: - if(!(rdr->typ == R_EMU && caid_is_biss(er->caid)) && !chk_rfilter(er, rdr)) - { - cs_log_dbg(D_TRACE, "r-filter reader %s", rdr->label); - return (0); - } - - // Check ECM nanos: - if(!chk_class(er, &rdr->cltab, "reader", rdr->label)) - { - cs_log_dbg(D_TRACE, "class filter reader %s", rdr->label); - return (0); - } - - // CDS NL: check for right seca type - if(!is_network_reader(rdr) && er->caid == 0x100 && er->prid == 0x00006a - && !(er->ecm[8] == 0x00 && er->ecm[9] == 0x00)) // no empty ecm - { - if(er->ecm[8] == 0x00 && rdr->secatype == 2) - { - cs_log_dbg(D_TRACE, "Error: this is a nagra/mediaguard3 ECM and readertype is seca2!"); - return 0; // we dont send a nagra/mediaguard3 ecm to a seca2 reader! - } - - if((er->ecm[8] == 0x10) && (er->ecm[9] == 0x01) && rdr->secatype == 3) - { - cs_log_dbg(D_TRACE, "Error: this is a seca2 ECM and readertype is nagra/mediaguard3!"); - return 0; // we dont send a seca2 ecm to a nagra/mediaguard3 reader! - } - } - - // CDS NL: check for right seca type by ECMPID - if(!is_network_reader(rdr) && er->caid == 0x100 && er->prid == 0x00006a) - { - if(rdr->secatype == 2 && er->pid >> 8 == 7) - { - cs_log_dbg(D_TRACE, "Error: this is a nagra/mediaguard3 ECM and readertype is seca2!"); - return 0; // we dont send a nagra/mediaguard3 ecm to a seca2 reader! - } - - if(rdr->secatype == 3 && er->pid >> 8 == 6) - { - cs_log_dbg(D_TRACE, "Error: this is a seca2 ECM and readertype is nagra/mediaguard3!"); - return 0; // we dont send a seca2 ecm to a nagra/mediaguard3 reader! - } - } - - // Checking chid: - if(!chk_chid(er, &rdr->fchid, "reader", rdr->label)) - { - cs_log_dbg(D_TRACE, "chid filter reader %s", rdr->label); - return (0); - } - - // Schlocke reader-defined function, reader-self-check - if(rdr->ph.c_available && !rdr->ph.c_available(rdr, AVAIL_CHECK_CONNECTED, er)) - { - cs_log_dbg(D_TRACE, "reader unavailable %s", rdr->label); - return 0; - } - - // Checking entitlements: - if(ll_count(rdr->ll_entitlements) > 0 && !(rdr->typ == R_EMU)) - { - LL_ITER itr = ll_iter_create(rdr->ll_entitlements); - S_ENTITLEMENT *item; - int8_t found = 0; - - while((item = ll_iter_next(&itr))) - { - if(item->caid != er->caid) continue; // skip wrong caid! - if(item->type == 7) continue; // skip seca-admin type (provid 000000) since its not used for decoding! - if(er->prid && item->provid && er->prid != item->provid) continue; // skip non matching provid! - if(!er->prid && caid_is_seca(er->caid)) continue; // dont accept requests without provid for seca cas. - if(!er->prid && caid_is_viaccess(er->caid)) continue; // dont accept requests without provid for viaccess cas - if(!er->prid && caid_is_cryptoworks(er->caid)) continue; // dont accept requests without provid for cryptoworks cas - found =1; - break; - } - - if(!found && er->ecm[0]) // ecmrequest can get corrected provid parsed from payload in ecm - { - cs_log_dbg(D_TRACE, "entitlements check failed on reader %s", rdr->label); - return 0; - } - } - - // Checking ecmlength: - if(rdr->ecm_whitelist.ewnum && er->ecmlen) - { - int32_t i; - int8_t ok = 0, foundident = 0; - - for (i = 0; i < rdr->ecm_whitelist.ewnum; i++) - { - ECM_WHITELIST_DATA *d = &rdr->ecm_whitelist.ewdata[i]; - if ((d->caid == 0 || d->caid == er->caid) && (d->ident == 0 || d->ident == er->prid)) - { - foundident = 1; - if (d->len == er->ecmlen) - { - ok = 1; - break; - } - } - } - - if(foundident == 1 && ok == 0) - { - cs_log_dbg(D_TRACE, "ECM is not in ecmwhitelist of reader %s.", rdr->label); - rdr->ecmsfilteredlen += 1; - rdr->webif_ecmsfilteredlen += 1; - return (0); - } - } - - // ECM Header Check - if(rdr->ecm_hdr_whitelist.ehdata && er->ecmlen) - { - int8_t byteok = 0; - int8_t entryok = 0; - int8_t foundcaid = 0; - int8_t foundprovid = 0; - int16_t len = 0; - int32_t i = 0; - int8_t skip = 0; - int32_t r; - - for(r = 0; r < rdr->ecm_hdr_whitelist.ehnum; r++) - { - ECM_HDR_WHITELIST_DATA *tmp = &rdr->ecm_hdr_whitelist.ehdata[r]; - skip = 0; - byteok = 0; - entryok = 0; - - if(tmp->caid == 0 || tmp->caid == er->caid) - { - foundcaid = 1; //-> caid was in list - //rdr_log_dbg(rdr, D_READER, "Headerwhitelist: found matching CAID: %04X in list", tmp->caid); - - if(tmp->provid == 0 || tmp->provid == er->prid) - { - foundprovid = 1; //-> provid was in list - //rdr_log_dbg(rdr, D_READER, "Headerwhitelist: found matching Provid: %06X in list", tmp->provid); - - len = tmp->len; - for(i = 0; i < len / 2; i++) - { - if(tmp->header[i] == er->ecm[i]) - { - byteok = 1; - //rdr_log_dbg(rdr, D_READER, "ECM Byte: %i of ECMHeaderwhitelist is correct. (%02X = %02X Headerlen: %i)", i, er->ecm[i], tmp->header[i], len/2); - } - else - { - byteok = 0; - //rdr_log_dbg(rdr, D_READER, "ECM Byte: %i of ECMHeaderwhitelist is not valid. (%02X != %02X Headerlen: %i)", i, er->ecm[i], tmp->header[i], len/2); - entryok = 0; - break; - } - - if(i == len / 2 - 1 && byteok == 1) - { - entryok = 1; - } - } - } - else - { - //rdr_log_dbg(rdr, D_READER, "ECMHeaderwhitelist: Provid: %06X not found in List-Entry -> skipping check", er->prid); - skip = 1; - continue; - } - } - else - { - //rdr_log_dbg(rdr, D_READER, "ECMHeaderwhitelist: CAID: %04X not found in List-Entry -> skipping check", er->caid); - skip = 1; - continue; - } - - if(entryok == 1) - { - break; - } - } - - if(foundcaid == 1 && foundprovid == 1 && byteok == 1 && entryok == 1) - { - //cs_log("ECM for %04X@%06X:%04X is valid for ECMHeaderwhitelist of reader %s.", er->caid, er->prid, er->srvid, rdr->label); - } - else - { - if(skip == 0 || (foundcaid == 1 && foundprovid == 1 && entryok == 0 && skip == 1)) - { - cs_log_dump_dbg(D_TRACE, er->ecm, er->ecmlen, "following ECM %04X@%06X:%04X was filtered by ECMHeaderwhitelist of Reader %s from User %s because of not matching Header:", er->caid, er->prid, er->srvid, rdr->label, username(er->client)); - rdr->ecmsfilteredhead += 1; - rdr->webif_ecmsfilteredhead += 1; - return (0); - } - } - } - - // Simple ring connection check: - - // Check ip source+dest: - if(cfg.block_same_ip && IP_EQUAL(cur_cl->ip, rdr->client->ip) && get_module(cur_cl)->listenertype != LIS_DVBAPI && is_network_reader(rdr)) - { - rdr_log_dbg(rdr, D_TRACE, "User (%s) has the same ip (%s) as the reader, blocked because block_same_ip=1!", username(cur_cl), cs_inet_ntoa(rdr->client->ip)); - return 0; - } - - if(cfg.block_same_name && strcmp(username(cur_cl), rdr->label) == 0) - { - rdr_log_dbg(rdr, D_TRACE, "User (%s) has the same name as the reader, blocked because block_same_name=1!", username(cur_cl)); - return 0; - } - - if(!reader_slots_available(rdr, er)&& er->ecmlen > 0) // check free slots, er->ecmlen>0 trick to skip this test for matching readers in dvbapi module - { - return 0; - } - - // All checks done, reader is matching! - return (1); -} - -int32_t chk_caid(uint16_t caid, CAIDTAB *ctab) -{ - int32_t i; - - if (!ctab->ctnum) { return caid; } - - for(i = 0; i < ctab->ctnum; i++) - { - CAIDTAB_DATA *d = &ctab->ctdata[i]; - if((caid & d->mask) == d->caid) { return d->cmap ? d->cmap : caid; } - } - return -1; -} - -int32_t chk_caid_rdr(struct s_reader *rdr, uint16_t caid) -{ - if(is_network_reader(rdr) || rdr->typ == R_EMU) - { - return 1; // reader caid is not real caid - } - else if(rdr->caid == caid) - { - return 1; - } - return 0; -} - -int32_t chk_bcaid(ECM_REQUEST *er, CAIDTAB *ctab) -{ - int32_t caid; - caid = chk_caid(er->caid, ctab); - if(caid < 0) { return 0; } - er->caid = caid; - return 1; -} - -/** - * Check for NULL CWs - **/ -int32_t chk_is_null_CW(uint8_t cw[]) -{ - int8_t i; - for(i = 0; i < 16; i++) - { - if(cw[i]) - { return 0; } - } - return 1; -} - -/** - * Check for ecm request that expects half cw format - **/ -int8_t is_halfCW_er(ECM_REQUEST *er) -{ - if(caid_is_videoguard(er->caid) && (er->caid != 0x09C7 && er->caid != 0x09EF)) - { return 1; } - return 0; -} - -/** - * Check for wrong half CWs - **/ -int8_t chk_halfCW(ECM_REQUEST *er, uint8_t *cw) -{ - if(is_halfCW_er(er) && cw) - { - uint8_t cw15 = cw[15]; - if(get_odd_even(er) == 0x80 && cw[15] == 0xF0) { cw[15] = 0; } - - int8_t part1 = checkCWpart(cw, 0); - int8_t part2 = checkCWpart(cw, 1); - - // check for correct half cw format - if(part1 && part2){ cw[15] = cw15; return 0; } - - // check for correct cw position - if((get_odd_even(er) == 0x80 && part1 && !part2) // xxxxxxxx00000000 - ||(get_odd_even(er) == 0x81 && !part1 && part2)) // 00000000xxxxxxxx - { - return 1; - } - - cw[15] = cw15; - return 0; // not correct swapped cw - } - else - { - return 1; - } -} - -/** - * Check for NULL nodeid - **/ -int32_t chk_is_null_nodeid(uint8_t node_id[]) -{ - int8_t i; - for(i = 0; i < 8; i++) - { - if(node_id[i]) { return 0; } - } - return 1; -} - -// check if client structure is accessible -bool check_client(struct s_client *cl) -{ - if(cl && !cl->kill) { return true; } - return false; -} - -uint16_t caidvaluetab_get_value(CAIDVALUETAB *cv, uint16_t caid, uint16_t default_value) -{ - int32_t i; - for(i = 0; i < cv->cvnum; i++) - { - CAIDVALUETAB_DATA *cvdata = &cv->cvdata[i]; - if(cvdata->caid == caid || cvdata->caid == caid >> 8) { return cvdata->value; } - } - return default_value; -} - -int32_t chk_is_fakecw(uint8_t *cw) -{ - uint32_t i, is_fakecw = 0; - uint32_t idx = ((cw[0] & 0xF) << 4) | (cw[8] & 0xF); - - cs_readlock(__func__, &config_lock); - - for(i = 0; i < cfg.fakecws[idx].count; i++) - { - if(memcmp(cw, cfg.fakecws[idx].data[i].cw, 16) == 0) - { - is_fakecw = 1; - break; - } - } - cs_readunlock(__func__, &config_lock); - - return is_fakecw; -} - -#ifdef CS_CACHEEX_AIO -bool chk_nopushafter(uint16_t caid, CAIDVALUETAB *cv, int32_t ecm_time) -{ - uint16_t npa_time = caidvaluetab_get_value(cv, caid, 0); - if(npa_time && (ecm_time > npa_time)) - { - cs_log_dbg(D_CACHEEX, "REJECTED push: nopushafter %u < ecm_time %i", npa_time, ecm_time); - return 0; - } - else - return 1; -} -#endif diff --git a/oscam-chk.c.rej b/oscam-chk.c.rej deleted file mode 100755 index 9a39ab3..0000000 --- a/oscam-chk.c.rej +++ /dev/null @@ -1,11 +0,0 @@ ---- oscam-chk.c (revision 11871) -+++ oscam-chk.c (working copy) -@@ -1213,7 +1213,7 @@ - **/ - int8_t is_halfCW_er(ECM_REQUEST *er) - { -- if( caid_is_videoguard(er->caid) && (er->caid == 0x09C4 || er->caid == 0x098C || er->caid == 0x098D || er->caid == 0x0963 || er->caid == 0x09CD || er->caid == 0x0919 || er->caid == 0x093B || er->caid == 0x098E)) -+ if( caid_is_videoguard(er->caid) && (er->caid == 0x098C || er->caid == 0x098D || er->caid == 0x098E || er->caid == 0x09BD || er->caid == 0x0963 || er->caid == 0x09CD || er->caid == 0x0919 || er->caid == 0x093B)) - { return 1; } - return 0; - } diff --git a/oscam-chk.h b/oscam-chk.h old mode 100644 new mode 100755 diff --git a/oscam-client.c b/oscam-client.c old mode 100644 new mode 100755 diff --git a/oscam-client.h b/oscam-client.h old mode 100644 new mode 100755 diff --git a/oscam-conf-chk.c b/oscam-conf-chk.c old mode 100644 new mode 100755 diff --git a/oscam-conf-chk.h b/oscam-conf-chk.h old mode 100644 new mode 100755 diff --git a/oscam-conf-mk.c b/oscam-conf-mk.c old mode 100644 new mode 100755 diff --git a/oscam-conf-mk.h b/oscam-conf-mk.h old mode 100644 new mode 100755 diff --git a/oscam-conf.c b/oscam-conf.c old mode 100644 new mode 100755 diff --git a/oscam-conf.h b/oscam-conf.h old mode 100644 new mode 100755 diff --git a/oscam-config-account.c b/oscam-config-account.c old mode 100644 new mode 100755 diff --git a/oscam-config-global.c b/oscam-config-global.c old mode 100644 new mode 100755 diff --git a/oscam-config-global.c.bak b/oscam-config-global.c.bak old mode 100644 new mode 100755 diff --git a/oscam-config-reader.c b/oscam-config-reader.c old mode 100644 new mode 100755 diff --git a/oscam-config.c b/oscam-config.c old mode 100644 new mode 100755 diff --git a/oscam-config.c.orig b/oscam-config.c.orig deleted file mode 100755 index 8fd7c32..0000000 --- a/oscam-config.c.orig +++ /dev/null @@ -1,1494 +0,0 @@ -#define MODULE_LOG_PREFIX "config" - -//FIXME Not checked on threadsafety yet; after checking please remove this line - -#include "globals.h" - -#include "oscam-conf.h" -#include "oscam-conf-chk.h" -#include "oscam-config.h" -#include "oscam-files.h" -#include "oscam-garbage.h" -#include "oscam-lock.h" -#include "oscam-string.h" -#include "oscam-time.h" - -#define cs_srid "oscam.srvid" -#define cs_ratelimit "oscam.ratelimit" -#define cs_trid "oscam.tiers" -#define cs_sidt "oscam.services" -#define cs_whitelist "oscam.whitelist" -#define cs_provid "oscam.provid" -#define cs_fakecws "oscam.fakecws" -#define cs_twin "oscam.twin" - -uint32_t cfg_sidtab_generation = 1; -uint32_t caid; - -extern char cs_confdir[]; - -char *get_config_filename(char *dest, size_t destlen, const char *filename) -{ - // cs_confdir is always terminated with / - snprintf(dest, destlen, "%s%s", cs_confdir, filename); - return dest; -} - -int32_t write_services(void) -{ - int32_t i; - struct s_sidtab *sidtab = cfg.sidtab; - char *ptr; - FILE *f = create_config_file(cs_sidt); - if(!f) - { return 1; } - - while(sidtab != NULL) - { - ptr = sidtab->label; - while(*ptr) - { - if(*ptr == ' ') { *ptr = '_'; } - ptr++; - } - fprintf(f, "[%s]\n", sidtab->label); -#ifdef CS_CACHEEX_AIO - fprintf_conf(f, "disablecrccws_only_for_exception", "%u", sidtab->disablecrccws_only_for_exception); // it should not have \n at the end - fputc((int)'\n', f); - fprintf_conf(f, "no_wait_time", "%u", sidtab->no_wait_time); // it should not have \n at the end - fputc((int)'\n', f); - fprintf_conf(f, "lg_only_exception", "%u", sidtab->lg_only_exception); // it should not have \n at the end - fputc((int)'\n', f); -#endif - fprintf_conf(f, "caid", "%s", ""); // it should not have \n at the end - for(i = 0; i < sidtab->num_caid; i++) - { - if(i == 0) { fprintf(f, "%04X", sidtab->caid[i]); } - else { fprintf(f, ",%04X", sidtab->caid[i]); } - } - fputc((int)'\n', f); - fprintf_conf(f, "provid", "%s", ""); // it should not have \n at the end - for(i = 0; i < sidtab->num_provid; i++) - { - if(i == 0) { fprintf(f, "%06X", sidtab->provid[i]); } - else { fprintf(f, ",%06X", sidtab->provid[i]); } - } - fputc((int)'\n', f); - fprintf_conf(f, "srvid", "%s", ""); // it should not have \n at the end - for(i = 0; i < sidtab->num_srvid; i++) - { - if(i == 0) { fprintf(f, "%04X", sidtab->srvid[i]); } - else { fprintf(f, ",%04X", sidtab->srvid[i]); } - } - fprintf(f, "\n\n"); - sidtab = sidtab->next; - } - - return flush_config_file(f, cs_sidt); -} - -void free_sidtab(struct s_sidtab *ptr) -{ - if(!ptr) { return; } - add_garbage(ptr->caid); //no need to check on NULL first, freeing NULL doesnt do anything - add_garbage(ptr->provid); - add_garbage(ptr->srvid); - add_garbage(ptr); -} - -static void chk_entry4sidtab(char *value, struct s_sidtab *sidtab, int32_t what) -{ - int32_t i, b; - char *ptr, *saveptr1 = NULL; - uint16_t *slist = (uint16_t *) 0; - uint32_t *llist = (uint32_t *) 0; -#ifdef CS_CACHEEX_AIO - uint8_t disablecrccws_only_for_exception = 0; - uint8_t no_wait_time = 0; - uint8_t lg_only_exception = 0; -#endif - char buf[cs_strlen(value) + 1]; - cs_strncpy(buf, value, sizeof(buf)); - -#ifdef CS_CACHEEX_AIO - if(what == 5) // lg_only_exception - { - sidtab->lg_only_exception = a2i(buf, sizeof(lg_only_exception)); - return; - } - - if(what == 4) // no_wait_time - { - sidtab->no_wait_time = a2i(buf, sizeof(no_wait_time)); - return; - } - - if(what == 3) // disablecrccws_only_for_exception - { - sidtab->disablecrccws_only_for_exception = a2i(buf, sizeof(disablecrccws_only_for_exception)); - return; - } -#endif - - b = (what == 1) ? sizeof(uint32_t) : sizeof(uint16_t); - - for(i = 0, ptr = strtok_r(value, ",", &saveptr1); ptr; ptr = strtok_r(NULL, ",", &saveptr1)) - { - caid = a2i(ptr, b); - if(!errno) { i++; } - } - //if (!i) return(0); - if(b == sizeof(uint16_t)) - { - if(!cs_malloc(&slist, i * sizeof(uint16_t))) { return; } - } - else - { - if(!cs_malloc(&llist, i * sizeof(uint32_t))) { return; } - } - cs_strncpy(value, buf, sizeof(buf)); - for(i = 0, ptr = strtok_r(value, ",", &saveptr1); ptr; ptr = strtok_r(NULL, ",", &saveptr1)) - { - caid = a2i(ptr, b); - if(errno) { continue; } - if(b == sizeof(uint16_t)) - { slist[i++] = (uint16_t) caid; } - else - { llist[i++] = caid; } - } - switch(what) - { - case 0: - add_garbage(sidtab->caid); - sidtab->caid = slist; - sidtab->num_caid = i; - break; - case 1: - add_garbage(sidtab->provid); - sidtab->provid = llist; - sidtab->num_provid = i; - break; - case 2: - add_garbage(sidtab->srvid); - sidtab->srvid = slist; - sidtab->num_srvid = i; - break; - } -} - -void chk_sidtab(char *token, char *value, struct s_sidtab *sidtab) -{ - if(!strcmp(token, "caid")) - { - chk_entry4sidtab(value, sidtab, 0); - return; - } - if(!strcmp(token, "provid")) - { - chk_entry4sidtab(value, sidtab, 1); - return; - } - if(!strcmp(token, "ident")) - { - chk_entry4sidtab(value, sidtab, 1); - return; - } - if(!strcmp(token, "srvid")) - { - chk_entry4sidtab(value, sidtab, 2); - return; - } -#ifdef CS_CACHEEX_AIO - if(!strcmp(token, "disablecrccws_only_for_exception")) - { - chk_entry4sidtab(value, sidtab, 3); - return; - } - if(!strcmp(token, "no_wait_time")) - { - chk_entry4sidtab(value, sidtab, 4); - return; - } - if(!strcmp(token, "lg_only_exception")) - { - chk_entry4sidtab(value, sidtab, 5); - return; - } -#endif - if(token[0] != '#') - { fprintf(stderr, "Warning: keyword '%s' in sidtab section not recognized\n", token); } -} - -void init_free_sidtab(void) -{ - struct s_sidtab *nxt, *ptr = cfg.sidtab; - while(ptr) - { - nxt = ptr->next; - free_sidtab(ptr); - ptr = nxt; - } - cfg.sidtab = NULL; - ++cfg_sidtab_generation; -} - -//#define DEBUG_SIDTAB 1 -#ifdef DEBUG_SIDTAB -static void show_sidtab(struct s_sidtab *sidtab) -{ - for(; sidtab; sidtab = sidtab->next) - { - int32_t i; - char buf[1024]; - char *saveptr = buf; - cs_log("label=%s", sidtab->label); -#ifdef CS_CACHEEX_AIO - cs_log("disablecrccws_only_for_exception=%u", sidtab->disablecrccws_only_for_exception); - cs_log("no_wait_time=%u", sidtab->no_wait_time); - cs_log("lg_only_exception=%u", sidtab->lg_only_exception); -#endif - snprintf(buf, sizeof(buf), "caid(%d)=", sidtab->num_caid); - for(i = 0; i < sidtab->num_caid; i++) - { snprintf(buf + cs_strlen(buf), 1024 - (buf - saveptr), "%04X ", sidtab->caid[i]); } - cs_log("%s", buf); - snprintf(buf, sizeof(buf), "provider(%d)=", sidtab->num_provid); - for(i = 0; i < sidtab->num_provid; i++) - { snprintf(buf + cs_strlen(buf), 1024 - (buf - saveptr), "%08X ", sidtab->provid[i]); } - cs_log("%s", buf); - snprintf(buf, sizeof(buf), "services(%d)=", sidtab->num_srvid); - for(i = 0; i < sidtab->num_srvid; i++) - { snprintf(buf + cs_strlen(buf), 1024 - (buf - saveptr), "%04X ", sidtab->srvid[i]); } - cs_log("%s", buf); - } -} -#else -static void show_sidtab(struct s_sidtab *UNUSED(sidtab)) { } -#endif - -int32_t init_sidtab(void) -{ - FILE *fp = open_config_file(cs_sidt); - if(!fp) - { return 1; } - - int32_t nr, nro, nrr; - char *value, *token; - if(!cs_malloc(&token, MAXLINESIZE)) - { return 1; } - struct s_sidtab *ptr; - struct s_sidtab *sidtab = (struct s_sidtab *)0; - - for(nro = 0, ptr = cfg.sidtab; ptr; nro++) - { - struct s_sidtab *ptr_next; - ptr_next = ptr->next; - free_sidtab(ptr); - ptr = ptr_next; - } - nr = 0; - nrr = 0; - while(fgets(token, MAXLINESIZE, fp)) - { - int32_t l; - if((l = cs_strlen(trim(token))) < 3) { continue; } - if((token[0] == '[') && (token[l - 1] == ']')) - { - token[l - 1] = 0; - if(nr > MAX_SIDBITS) - { - fprintf(stderr, "Warning: Service No.%d - '%s' ignored. Max allowed Services %d\n", nr, strtolower(token + 1), MAX_SIDBITS); - nr++; - nrr++; - } - else - { - if(!cs_malloc(&ptr, sizeof(struct s_sidtab))) - { - NULLFREE(token); - return (1); - } - if(sidtab) - { sidtab->next = ptr; } - else - { cfg.sidtab = ptr; } - sidtab = ptr; - nr++; - cs_strncpy(sidtab->label, strtolower(token + 1), sizeof(sidtab->label)); - continue; - } - } - if(!sidtab) { continue; } - if(!(value = strchr(token, '='))) { continue; } - *value++ = '\0'; - chk_sidtab(trim(strtolower(token)), trim(strtolower(value)), sidtab); - } - NULLFREE(token); - fclose(fp); - - show_sidtab(cfg.sidtab); - ++cfg_sidtab_generation; - cs_log("services reloaded: %d services freed, %d services loaded, rejected %d", nro, nr, nrr); - return (0); -} - -int32_t init_provid(void) -{ - FILE *fp = open_config_file(cs_provid); - if(!fp) - { return 0; } - - int32_t nr; - char *payload, *saveptr1 = NULL, *token; - if(!cs_malloc(&token, MAXLINESIZE)) - { return 0; } - struct s_provid *provid_ptr = NULL; - struct s_provid *new_cfg_provid = NULL, *last_provid; - - nr = 0; - while(fgets(token, MAXLINESIZE, fp)) - { - int32_t i; - struct s_provid *new_provid = NULL; - char *tmp, *ptr1; - - tmp = trim(token); - - if(tmp[0] == '#') { continue; } - if(cs_strlen(tmp) < 11) { continue; } - if(!(payload = strchr(token, '|'))) { continue; } - - *payload++ = '\0'; - - if(!cs_malloc(&new_provid, sizeof(struct s_provid))) - { - NULLFREE(token); - fclose(fp); - return (1); - } - - new_provid->nprovid = 0; - for(i = 0, ptr1 = strtok_r(token, ":@", &saveptr1); ptr1; ptr1 = strtok_r(NULL, ":@", &saveptr1), i++) - { - if(i==0) - { - new_provid->caid = a2i(ptr1, 3); - continue; - } - - new_provid->nprovid++; - } - - if(!cs_malloc(&new_provid->provid, sizeof(uint32_t) * new_provid->nprovid)) - { - NULLFREE(new_provid); - NULLFREE(token); - fclose(fp); - return (1); - } - - ptr1 = token + cs_strlen(token) + 1; - for(i = 0; i < new_provid->nprovid ; i++) - { - new_provid->provid[i] = a2i(ptr1, 3); - - ptr1 = ptr1 + cs_strlen(ptr1) + 1; - } - - for(i = 0, ptr1 = strtok_r(payload, "|", &saveptr1); ptr1; ptr1 = strtok_r(NULL, "|", &saveptr1), i++) - { - switch(i) - { - case 0: - cs_strncpy(new_provid->prov, trim(ptr1), sizeof(new_provid->prov)); - break; - case 1: - cs_strncpy(new_provid->sat, trim(ptr1), sizeof(new_provid->sat)); - break; - case 2: - cs_strncpy(new_provid->lang, trim(ptr1), sizeof(new_provid->lang)); - break; - } - } - - if(cs_strlen(new_provid->prov) == 0) - { - NULLFREE(new_provid->provid); - NULLFREE(new_provid); - continue; - } - - nr++; - - if(provid_ptr) - { - provid_ptr->next = new_provid; - } - else - { - new_cfg_provid = new_provid; - } - provid_ptr = new_provid; - } - - NULLFREE(token); - fclose(fp); - - if(nr > 0) - { cs_log("%d provid's loaded", nr); } - - if(new_cfg_provid == NULL) - { - if(!cs_malloc(&new_cfg_provid, sizeof(struct s_provid))) - { - return (1); - } - } - - cs_writelock(__func__, &config_lock); - - // this allows reloading of provids, so cleanup of old data is needed: - last_provid = cfg.provid; // old data - cfg.provid = new_cfg_provid; // assign after loading, so everything is in memory - - cs_writeunlock(__func__, &config_lock); - - struct s_client *cl; - for(cl = first_client->next; cl ; cl = cl->next) - { cl->last_providptr = NULL; } - - struct s_provid *ptr, *nptr; - - if(last_provid) - { - ptr = last_provid; - while(ptr) // cleanup old data: - { - add_garbage(ptr->provid); - nptr = ptr->next; - add_garbage(ptr); - ptr = nptr; - } - } - - return (0); -} - -int32_t init_srvid(void) -{ - int8_t new_syntax = 1; - FILE *fp = open_config_file("oscam.srvid2"); - if(!fp) - { - fp = open_config_file(cs_srid); - if(fp) - { - new_syntax = 0; - } - } - - if(!fp) - { - fp = create_config_file("oscam.srvid2"); - if(fp) - { - flush_config_file(fp, "oscam.srvid2"); - } - - return 0; - } - - int32_t nr = 0, i, j; - char *payload, *saveptr1 = NULL, *saveptr2 = NULL, *token; - const char *tmp; - if(!cs_malloc(&token, MAXLINESIZE)) - { return 0; } - struct s_srvid *srvid = NULL, *new_cfg_srvid[16], *last_srvid[16]; - // A cache for strings within srvids. A checksum is calculated which is the start point in the array (some kind of primitive hash algo). - // From this point, a sequential search is done. This greatly reduces the amount of string comparisons. - const char **stringcache[1024]; - int32_t allocated[1024] = { 0 }; - int32_t used[1024] = { 0 }; - struct timeb ts, te; - cs_ftime(&ts); - - memset(last_srvid, 0, sizeof(last_srvid)); - memset(new_cfg_srvid, 0, sizeof(new_cfg_srvid)); - - while(fgets(token, MAXLINESIZE, fp)) - { - int32_t len = 0, len2, srvidtmp; - uint32_t k; - uint32_t pos; - char *srvidasc, *prov; - tmp = trim(token); - - if(tmp[0] == '#') { continue; } - if(cs_strlen(tmp) < 6) { continue; } - if(!(srvidasc = strchr(token, ':'))) { continue; } - if(!(payload = strchr(token, '|'))) { continue; } - *payload++ = '\0'; - - if(!cs_malloc(&srvid, sizeof(struct s_srvid))) - { - NULLFREE(token); - fclose(fp); - return (1); - } - - char tmptxt[128]; - - int32_t offset[4] = { -1, -1, -1, -1 }; - char *ptr1 = NULL, *ptr2 = NULL; - const char *searchptr[4] = { NULL, NULL, NULL, NULL }; - const char **ptrs[4] = { &srvid->prov, &srvid->name, &srvid->type, &srvid->desc }; - uint32_t max_payload_length = MAXLINESIZE - (payload - token); - - if(new_syntax) - { - ptrs[0] = &srvid->name; - ptrs[1] = &srvid->type; - ptrs[2] = &srvid->desc; - ptrs[3] = &srvid->prov; - } - - // allow empty strings as "||" - if(payload[0] == '|' && (cs_strlen(payload) + 2 < max_payload_length)) - { - memmove(payload+1, payload, cs_strlen(payload)+1); - payload[0] = ' '; - } - - for(k = 1; ((k < max_payload_length) && (payload[k] != '\0')); k++) - { - if(payload[k - 1] == '|' && payload[k] == '|') - { - if(cs_strlen(payload + k) + 2 < max_payload_length-k) - { - memmove(payload + k + 1, payload + k, cs_strlen(payload + k) + 1); - payload[k] = ' '; - } - else - { - break; - } - } - } - - for(i = 0, ptr1 = strtok_r(payload, "|", &saveptr1); ptr1 && (i < 4) ; ptr1 = strtok_r(NULL, "|", &saveptr1), ++i) - { - // check if string is in cache - len2 = cs_strlen(ptr1); - pos = 0; - for(j = 0; j < len2; ++j) { pos += (uint8_t)ptr1[j]; } - pos = pos % 1024; - for(j = 0; j < used[pos]; ++j) - { - if(!strcmp(stringcache[pos][j], ptr1)) - { - searchptr[i] = stringcache[pos][j]; - break; - } - } - if(searchptr[i]) { continue; } - - offset[i] = len; - cs_strncpy(tmptxt + len, trim(ptr1), sizeof(tmptxt) - len); - len += cs_strlen(ptr1) + 1; - } - - char *tmpptr = NULL; - if(len > 0 && !cs_malloc(&tmpptr, len)) - { continue; } - - srvid->data = tmpptr; - if(len > 0) { memcpy(tmpptr, tmptxt, len); } - - for(i = 0; i < 4; i++) - { - if(searchptr[i]) - { - *ptrs[i] = searchptr[i]; - continue; - } - if(offset[i] > -1) - { - *ptrs[i] = tmpptr + offset[i]; - // store string in stringcache - if (*ptrs[i]) - { - tmp = *ptrs[i]; - len2 = cs_strlen(tmp); - } - else - { - cs_log("FIXME! len2!"); - len2 = 0; - } - - pos = 0; - for(j = 0; j < len2; ++j) { pos += (uint8_t)tmp[j]; } - if (pos > 0) - { - pos = pos % 1024; - } - if(used[pos] >= allocated[pos]) - { - if(allocated[pos] == 0) - { - if(!cs_malloc(&stringcache[pos], 16 * sizeof(char *))) - { break; } - } - else - { - if(!cs_realloc(&stringcache[pos], (allocated[pos] + 16) * sizeof(char *))) - { break; } - } - allocated[pos] += 16; - } - if (tmp[0]) - { - stringcache[pos][used[pos]] = tmp; - used[pos] += 1; - } - } - } - - *srvidasc++ = '\0'; - if(new_syntax) - { srvidtmp = dyn_word_atob(token) & 0xFFFF; } - else - { srvidtmp = dyn_word_atob(srvidasc) & 0xFFFF; } - - if(srvidtmp < 0) - { - NULLFREE(tmpptr); - NULLFREE(srvid); - continue; - } - else - { - srvid->srvid = srvidtmp; - } - - srvid->ncaid = 0; - for(i = 0, ptr1 = strtok_r(new_syntax ? srvidasc : token, ",", &saveptr1); (ptr1); ptr1 = strtok_r(NULL, ",", &saveptr1), i++) - { - srvid->ncaid++; - } - - if(!cs_malloc(&srvid->caid, sizeof(struct s_srvid_caid) * srvid->ncaid)) - { - NULLFREE(tmpptr); - NULLFREE(srvid); - return 0; - } - - ptr1 = new_syntax ? srvidasc : token; - for(i = 0; i < srvid->ncaid; i++) - { - prov = strchr(ptr1,'@'); - - srvid->caid[i].nprovid = 0; - - if(prov) - { - if(prov[1] != '\0') - { - for(j = 0, ptr2 = strtok_r(prov+1, "@", &saveptr2); (ptr2); ptr2 = strtok_r(NULL, "@", &saveptr2), j++) - { - srvid->caid[i].nprovid++; - } - - if(!cs_malloc(&srvid->caid[i].provid, sizeof(uint32_t) * srvid->caid[i].nprovid)) - { - for(j = 0; j < i; j++) - { NULLFREE(srvid->caid[j].provid); } - NULLFREE(srvid->caid); - NULLFREE(tmpptr); - NULLFREE(srvid); - return 0; - } - - ptr2 = prov + 1; - for(j = 0; j < srvid->caid[i].nprovid; j++) - { - srvid->caid[i].provid[j] = dyn_word_atob(ptr2) & 0xFFFFFF; - ptr2 = ptr2 + cs_strlen(ptr2) + 1; - } - } - else - { - ptr2 = prov + 2; - } - - prov[0] = '\0'; - } - - srvid->caid[i].caid = dyn_word_atob(ptr1) & 0xFFFF; - if(prov) - { ptr1 = ptr2; } - else - { ptr1 = ptr1 + cs_strlen(ptr1) + 1; } - } - - nr++; - - if(new_cfg_srvid[srvid->srvid >> 12]) - { last_srvid[srvid->srvid >> 12]->next = srvid; } - else - { new_cfg_srvid[srvid->srvid >> 12] = srvid; } - - last_srvid[srvid->srvid >> 12] = srvid; - } - for(i = 0; i < 1024; ++i) - { - if(allocated[i] > 0) { NULLFREE(stringcache[i]); } - } - NULLFREE(token); - - cs_ftime(&te); - int64_t load_time = comp_timeb(&te, &ts); - - fclose(fp); - if(nr > 0) - { - cs_log("%d service-id's loaded in %"PRId64" ms", nr, load_time); - if(nr > 2000) - { - cs_log("WARNING: You risk high CPU load and high ECM times with more than 2000 service-id's!"); - cs_log("HINT: --> use optimized lists from %s/Srvid", WIKI_URL); - } - } - - cs_writelock(__func__, &config_lock); - // this allows reloading of srvids, so cleanup of old data is needed: - memcpy(last_srvid, cfg.srvid, sizeof(last_srvid)); //old data - memcpy(cfg.srvid, new_cfg_srvid, sizeof(last_srvid)); //assign after loading, so everything is in memory - - cs_writeunlock(__func__, &config_lock); - - struct s_client *cl; - for(cl = first_client->next; cl ; cl = cl->next) - { cl->last_srvidptr = NULL; } - - struct s_srvid *ptr, *nptr; - - for(i = 0; i < 16; i++) - { - ptr = last_srvid[i]; - while(ptr) // cleanup old data: - { - for(j = 0; j < ptr->ncaid; j++) - { add_garbage(ptr->caid[j].provid); } - add_garbage(ptr->caid); - add_garbage(ptr->data); - nptr = ptr->next; - add_garbage(ptr); - ptr = nptr; - } - } - - return (0); -} - -int32_t init_fakecws(void) -{ - int32_t nr = 0, i, j, idx; - uint32_t alloccount[0x100], count[0x100], tmp, max_compares = 0, average_compares = 0; - char *token, cw_string[64]; - uint8_t cw[16], wrong_checksum, c, have_fakecw = 0; - FILE *fp; - - memset(alloccount, 0, sizeof(count)); - memset(count, 0, sizeof(alloccount)); - - cs_writelock(__func__, &config_lock); - for(i = 0; i < 0x100; i++) - { - cfg.fakecws[i].count = 0; - NULLFREE(cfg.fakecws[i].data); - } - cs_writeunlock(__func__, &config_lock); - - fp = open_config_file(cs_fakecws); - if(!fp) - { return 0; } - - if(!cs_malloc(&token, MAXLINESIZE)) - { return 0; } - - while(fgets(token, MAXLINESIZE, fp)) - { - if(sscanf(token, " %62s ", cw_string) == 1) - { - if(cs_strlen(cw_string) == 32) - { - if(cs_atob(cw, cw_string, 16) == 16) - { - wrong_checksum = 0; - - if(wrong_checksum) - { - cs_log("skipping fake cw %s because of wrong checksum!", cw_string); - } - else - { - idx = ((cw[0] & 0xF) << 4) | (cw[8] & 0xF); - alloccount[idx]++; - have_fakecw = 1; - } - } - else - { - cs_log("skipping fake cw %s because it contains invalid characters!", cw_string); - } - } - else - { - cs_log("skipping fake cw %s because of wrong length (%u != 32)!", cw_string, (uint32_t)cs_strlen(cw_string)); - } - } - } - - if(!have_fakecw) - { - NULLFREE(token); - fclose(fp); - return 0; - } - - for(i = 0; i < 0x100; i++) - { - if(alloccount[i] && !cs_malloc(&cfg.fakecws[i].data, sizeof(struct s_cw)*alloccount[i])) - { - alloccount[i] = 0; - } - } - - fseek(fp, 0, SEEK_SET); - - while(fgets(token, MAXLINESIZE, fp)) - { - if(sscanf(token, " %62s ", cw_string) == 1) - { - if(cs_strlen(cw_string) == 32) - { - if(cs_atob(cw, cw_string, 16) == 16) - { - wrong_checksum = 0; - - if(!wrong_checksum) - { - idx = ((cw[0] & 0xF) << 4) | (cw[8] & 0xF); - - if(count[idx] < alloccount[idx]) - { - memcpy(cfg.fakecws[idx].data[count[idx]].cw, cw, 16); - count[idx]++; - nr++; - } - } - } - } - } - } - - NULLFREE(token); - fclose(fp); - - if(nr > 0) - { cs_log("%d fakecws's loaded", nr); } - - - cs_writelock(__func__, &config_lock); - for(i = 0; i < 0x100; i++) - { - cfg.fakecws[i].count = count[i]; - } - cs_writeunlock(__func__, &config_lock); - - - for(i = 0; i < 0x100; i++) - { - if(count[i] > max_compares) - { max_compares = count[i]; } - } - - for(i = 0; i < (0x100 - 1); i++) - { - for(j = i + 1; j < 0x100; j++) - { - if(count[j] < count[i]) - { - tmp = count[i]; - count[i] = count[j]; - count[j] = tmp; - } - } - } - average_compares = ((count[0x100 / 2] + count[0x100 / 2 - 1]) / 2); - - - cs_log("max %d fakecw compares required, on average: %d compares", max_compares, average_compares); - - return 0; -} - -static struct s_rlimit *ratelimit_read_int(void) -{ - FILE *fp = open_config_file(cs_ratelimit); - if(!fp) - { return NULL; } - char token[1024], str1[1024]; - int32_t i, ret, count = 0; - struct s_rlimit *new_rlimit = NULL, *entry, *last = NULL; - - while(fgets(token, sizeof(token), fp)) - { - if(cs_strlen(token) <= 1) { continue; } - if(token[0] == '#' || token[0] == '/') { continue; } - if(cs_strlen(token) > 1024) { continue; } - - for(i = 0; i < (int)cs_strlen(token); i++) - { - if((token[i] == ':' || token[i] == ' ') && token[i + 1] == ':') - { - memmove(token + i + 2, token + i + 1, cs_strlen(token) - i + 1); - token[i + 1] = '0'; - } - if(token[i] == '#' || token[i] == '/') - { - token[i] = '\0'; - break; - } - } - - caid = 0; - uint32_t provid = 0, srvid = 0, chid = 0, ratelimitecm = 0, ratelimittime = 0, srvidholdtime = 0; - memset(str1, 0, sizeof(str1)); - - ret = sscanf(token, "%4x:%6x:%4x:%4x:%d:%d:%d:%1023s", &caid, &provid, &srvid, &chid, &ratelimitecm, &ratelimittime, &srvidholdtime, str1); - if(ret < 1) { - continue; - } - - if (!cs_strncat(str1, ",", sizeof(str1))) { - return new_rlimit; - } - - if(!cs_malloc(&entry, sizeof(struct s_rlimit))) - { - fclose(fp); - return new_rlimit; - } - - count++; - if (ratelimittime < 60) ratelimittime *= 1000; - if (srvidholdtime < 60) srvidholdtime *= 1000; - entry->rl.caid = caid; - entry->rl.provid = provid; - entry->rl.srvid = srvid; - entry->rl.chid = chid; - entry->rl.ratelimitecm = ratelimitecm; - entry->rl.ratelimittime = ratelimittime; - entry->rl.srvidholdtime = srvidholdtime; - - cs_log_dbg(D_TRACE, "ratelimit: %04X@%06X:%04X:%04X:%d:%d:%d", entry->rl.caid, entry->rl.provid, entry->rl.srvid, entry->rl.chid, - entry->rl.ratelimitecm, entry->rl.ratelimittime, entry->rl.srvidholdtime); - - if(!new_rlimit) - { - new_rlimit = entry; - last = new_rlimit; - } - else - { - last->next = entry; - last = entry; - } - } - - if(count) - { cs_log("%d entries read from %s", count, cs_ratelimit); } - - fclose(fp); - - return new_rlimit; -} - -void ratelimit_read(void) -{ - - struct s_rlimit *entry, *old_list; - - old_list = cfg.ratelimit_list; - cfg.ratelimit_list = ratelimit_read_int(); - - while(old_list) - { - entry = old_list->next; - NULLFREE(old_list); - old_list = entry; - } -} - -struct ecmrl get_ratelimit(ECM_REQUEST *er) -{ - - struct ecmrl tmp; - memset(&tmp, 0, sizeof(tmp)); - if(!cfg.ratelimit_list) { return tmp; } - struct s_rlimit *entry = cfg.ratelimit_list; - while(entry) - { - if(entry->rl.caid == er->caid && entry->rl.provid == er->prid && entry->rl.srvid == er->srvid && (!entry->rl.chid || entry->rl.chid == er->chid)) - { - break; - } - entry = entry->next; - } - - if(entry) { tmp = entry->rl; } - - return (tmp); -} - -int32_t init_tierid(void) -{ - FILE *fp = open_config_file(cs_trid); - if(!fp) - { return 0; } - - int32_t nr; - char *payload, *saveptr1 = NULL, *token; - if(!cs_malloc(&token, MAXLINESIZE)) - { return 0; } - static struct s_tierid *tierid = NULL, *new_cfg_tierid = NULL; - - nr = 0; - while(fgets(token, MAXLINESIZE, fp)) - { - void *ptr; - char *tmp, *tieridasc; - tmp = trim(token); - - if(tmp[0] == '#') { continue; } - if(cs_strlen(tmp) < 6) { continue; } - if(!(payload = strchr(token, '|'))) { continue; } - if(!(tieridasc = strchr(token, ':'))) { continue; } - *payload++ = '\0'; - - if(!cs_malloc(&ptr, sizeof(struct s_tierid))) - { - NULLFREE(token); - fclose(fp); - return (1); - } - if(tierid) - { tierid->next = ptr; } - else - { new_cfg_tierid = ptr; } - - tierid = ptr; - - int32_t i; - char *ptr1 = strtok_r(payload, "|", &saveptr1); - if(ptr1) - { cs_strncpy(tierid->name, trim(ptr1), sizeof(tierid->name)); } - - *tieridasc++ = '\0'; - tierid->tierid = dyn_word_atob(tieridasc); - //printf("tierid %s - %d\n",tieridasc,tierid->tierid ); - - tierid->ncaid = 0; - for(i = 0, ptr1 = strtok_r(token, ",", &saveptr1); (ptr1) && (i < 10) ; ptr1 = strtok_r(NULL, ",", &saveptr1), i++) - { - tierid->caid[i] = dyn_word_atob(ptr1); - tierid->ncaid = i + 1; - //cs_log("ld caid: %04X tierid: %04X name: %s",tierid->caid[i],tierid->tierid,tierid->name); - } - nr++; - } - NULLFREE(token); - fclose(fp); - if(nr > 0) - { cs_log("%d tier-id's loaded", nr); } - cs_writelock(__func__, &config_lock); - // reload function: - tierid = cfg.tierid; - cfg.tierid = new_cfg_tierid; - struct s_tierid *ptr; - while(tierid) - { - ptr = tierid->next; - NULLFREE(tierid); - tierid = ptr; - } - cs_writeunlock(__func__, &config_lock); - - return (0); -} - -int32_t match_whitelist(ECM_REQUEST *er, struct s_global_whitelist *entry) -{ - return ((!entry->caid || entry->caid == er->caid) - && (!entry->provid || entry->provid == er->prid) - && (!entry->srvid || entry->srvid == er->srvid) - && (!entry->chid || entry->chid == er->chid) - && (!entry->pid || entry->pid == er->pid) - && (!entry->ecmlen || entry->ecmlen == er->ecmlen)); -} - -int32_t chk_global_whitelist(ECM_REQUEST *er, uint32_t *line) -{ - *line = -1; - if(!cfg.global_whitelist) - { return 1; } - - struct s_global_whitelist *entry; - - // check mapping: - if(cfg.global_whitelist_use_m) - { - entry = cfg.global_whitelist; - while(entry) - { - if(entry->type == 'm') - { - if(match_whitelist(er, entry)) - { - cs_log_dbg(D_TRACE, "whitelist: mapped %04X@%06X to %04X@%06X", er->caid, er->prid, entry->mapcaid, entry->mapprovid); - er->caid = entry->mapcaid; - er->prid = entry->mapprovid; - break; - } - } - entry = entry->next; - } - } - - if(cfg.global_whitelist_use_l) // Check caid/prov/srvid etc matching, except ecm-len: - { - entry = cfg.global_whitelist; - int8_t caidprov_matches = 0; - while(entry) - { - if(entry->type == 'l') - { - if(match_whitelist(er, entry)) - { - *line = entry->line; - return 1; - } - if((!entry->caid || entry->caid == er->caid) - && (!entry->provid || entry->provid == er->prid) - && (!entry->srvid || entry->srvid == er->srvid) - && (!entry->chid || entry->chid == er->chid) - && (!entry->pid || entry->pid == er->pid)) - { - caidprov_matches = 1; - *line = entry->line; - } - } - entry = entry->next; - } - if(caidprov_matches) // ...but not ecm-len! - { return 0; } - } - - entry = cfg.global_whitelist; - while(entry) - { - if(match_whitelist(er, entry)) - { - *line = entry->line; - if(entry->type == 'w') - { return 1; } - else if(entry->type == 'i') - { return 0; } - } - entry = entry->next; - } - return 0; -} - -//Format: -//Whitelist-Entry: -//w:caid:prov:srvid:pid:chid:ecmlen -//Ignore-Entry: -//i:caid:prov:srvid:pid:chid:ecmlen -//ECM len check - Entry: -//l:caid:prov:srvid:pid:chid:ecmlen - -//Mapping: -//m:caid:prov:srvid:pid:chid:ecmlen caidto:provto - -static struct s_global_whitelist *global_whitelist_read_int(void) -{ - FILE *fp = open_config_file(cs_whitelist); - if(!fp) - { return NULL; } - - char token[1024], str1[1024]; - uint8_t type; - int32_t i, ret, count = 0; - struct s_global_whitelist *new_whitelist = NULL, *entry, *last = NULL; - uint32_t line = 0; - - cfg.global_whitelist_use_l = 0; - cfg.global_whitelist_use_m = 0; - - while(fgets(token, sizeof(token), fp)) - { - line++; - if(cs_strlen(token) <= 1) { continue; } - if(token[0] == '#' || token[0] == '/') { continue; } - if(cs_strlen(token) > 1024) { continue; } - - for(i = 0; i < (int)cs_strlen(token); i++) - { - if((token[i] == ':' || token[i] == ' ') && token[i + 1] == ':') - { - memmove(token + i + 2, token + i + 1, cs_strlen(token) - i + 1); - token[i + 1] = '0'; - } - if(token[i] == '#' || token[i] == '/') - { - token[i] = '\0'; - break; - } - } - - type = 'w'; - caid = 0; - uint32_t provid = 0, srvid = 0, pid = 0, chid = 0, ecmlen = 0, mapcaid = 0, mapprovid = 0; - memset(str1, 0, sizeof(str1)); - - ret = sscanf(token, "%c:%4x:%6x:%4x:%4x:%4x:%1023s", &type, &caid, &provid, &srvid, &pid, &chid, str1); - - type = tolower(type); - - //w=whitelist - //i=ignore - //l=len-check - //m=map caid/prov - if(ret < 1 || (type != 'w' && type != 'i' && type != 'l' && type != 'm')) - { continue; } - - if(type == 'm') - { - char *p = strstr(token + 4, " "); - if(!p || sscanf(p + 1, "%4x:%6x", &mapcaid, &mapprovid) < 2) - { - cs_log_dbg(D_TRACE, "whitelist: wrong mapping: %s", token); - continue; - } - str1[0] = 0; - cfg.global_whitelist_use_m = 1; - } - - if (!cs_strncat(str1, ",", sizeof(str1))) { - return new_whitelist; - } - - char *p = str1, *p2 = str1; - - while(*p) - { - if(*p == ',') - { - *p = 0; - ecmlen = 0; - sscanf(p2, "%4x", &ecmlen); - - if(!cs_malloc(&entry, sizeof(struct s_global_whitelist))) - { - fclose(fp); - return new_whitelist; - } - - count++; - entry->line = line; - entry->type = type; - entry->caid = caid; - entry->provid = provid; - entry->srvid = srvid; - entry->pid = pid; - entry->chid = chid; - entry->ecmlen = ecmlen; - entry->mapcaid = mapcaid; - entry->mapprovid = mapprovid; - if(entry->type == 'l') - { cfg.global_whitelist_use_l = 1; } - - if(type == 'm') - cs_log_dbg(D_TRACE, "whitelist: %c: %04X@%06X:%04X:%04X:%04X:%02X map to %04X@%06X", - entry->type, entry->caid, entry->provid, entry->srvid, entry->pid, entry->chid, entry->ecmlen, entry->mapcaid, entry->mapprovid); - else - cs_log_dbg(D_TRACE, "whitelist: %c: %04X@%06X:%04X:%04X:%04X:%02X", - entry->type, entry->caid, entry->provid, entry->srvid, entry->pid, entry->chid, entry->ecmlen); - - if(!new_whitelist) - { - new_whitelist = entry; - last = new_whitelist; - } - else - { - last->next = entry; - last = entry; - } - - p2 = p + 1; - } - p++; - } - } - - if(count) - { cs_log("%d entries read from %s", count, cs_whitelist); } - - fclose(fp); - - return new_whitelist; -} - -void global_whitelist_read(void) -{ - struct s_global_whitelist *entry, *old_list; - - old_list = cfg.global_whitelist; - cfg.global_whitelist = global_whitelist_read_int(); - - while(old_list) - { - entry = old_list->next; - NULLFREE(old_list); - old_list = entry; - } -} - -#ifdef MODULE_SERIAL -static struct s_twin *twin_read_int(void) -{ - FILE *fp = open_config_file(cs_twin); - if(!fp) - { return NULL; } - char token[1024], str1[1024]; - int32_t i, ret, count = 0; - struct s_twin *new_twin = NULL, *entry, *last = NULL; - - while(fgets(token, sizeof(token), fp)) - { - if(cs_strlen(token) <= 1) { continue; } - if(token[0] == '#' || token[0] == '/') { continue; } - if(cs_strlen(token) > 1024) { continue; } - - for(i = 0; i < (int)cs_strlen(token); i++) - { - if((token[i] == ':' || token[i] == ' ') && token[i + 1] == ':') - { - memmove(token + i + 2, token + i + 1, cs_strlen(token) - i + 1); - token[i + 1] = '0'; - } - if(token[i] == '#' || token[i] == '/' || token[i] == '"') - { - token[i] = '\0'; - break; - } - } - - caid = 0; - uint32_t provid = 0, srvid = 0, deg = 0, freq = 0; - //char hdeg[4], hfreq[4], hsrvid[4]; - memset(str1, 0, sizeof(str1)); - - ret = sscanf(token, "%4x:%6x:%d:%d:%d", &caid, &provid, °, &freq, &srvid); - if(ret < 1) { continue; } - - //snprintf(hdeg, 4, "%x", deg); - //sscanf(hdeg, "%4x", °); - //snprintf(hfreq, 4, "%x", freq); - //sscanf(hfreq, "%4x", &freq); - //snprintf(hsrvid, 4, "%x", srvid); - //sscanf(hsrvid, "%4x", &srvid); - if (!cs_strncat(str1, ",", sizeof(str1))) { - return new_twin; - } - - if(!cs_malloc(&entry, sizeof(struct s_twin))) - { - fclose(fp); - return new_twin; - } - - count++; - entry->tw.caid = caid; - entry->tw.provid = provid; - entry->tw.srvid = srvid; - entry->tw.deg = deg; - entry->tw.freq = freq; - - cs_debug_mask(D_TRACE, "channel: %04X:%06X:%d:%d:%d", entry->tw.caid, - entry->tw.provid, entry->tw.deg, entry->tw.freq, entry->tw.srvid); - - if(!new_twin) - { - new_twin = entry; - last = new_twin; - } - else - { - last->next = entry; - last = entry; - } - } - - if(count) - { cs_log("%d entries read from %s", count, cs_twin); } - - fclose(fp); - - return new_twin; -} - -void twin_read(void) -{ - - struct s_twin *entry, *old_list; - - old_list = cfg.twin_list; - cfg.twin_list = twin_read_int(); - - while(old_list) - { - entry = old_list->next; - free(old_list); - old_list = entry; - } -} - -struct ecmtw get_twin(ECM_REQUEST *er) -{ - struct ecmtw tmp; - memset(&tmp, 0, sizeof(tmp)); - if(!cfg.twin_list) - { - cs_log("twin_list not found!"); - return tmp; - } - struct s_twin *entry = cfg.twin_list; - while(entry) - { - if(entry->tw.caid == er->caid && entry->tw.provid == er->prid && entry->tw.srvid == er->srvid) - { - break; - } - entry = entry->next; - } - - if(entry) { tmp = entry->tw; } - - return (tmp); -} -#endif diff --git a/oscam-config.h b/oscam-config.h old mode 100644 new mode 100755 diff --git a/oscam-ecm.c b/oscam-ecm.c old mode 100644 new mode 100755 diff --git a/oscam-ecm.c.bak b/oscam-ecm.c.bak old mode 100644 new mode 100755 diff --git a/oscam-ecm.c.orig b/oscam-ecm.c.orig deleted file mode 100755 index ecf3c16..0000000 --- a/oscam-ecm.c.orig +++ /dev/null @@ -1,3788 +0,0 @@ -#define MODULE_LOG_PREFIX "ecm" - -#include "globals.h" -#include -#include "cscrypt/md5.h" -#include "module-anticasc.h" -#include "module-cacheex.h" -#include "module-led.h" -#include "module-stat.h" -#include "module-webif.h" -#include "module-cw-cycle-check.h" -#include "module-gbox.h" -#include "oscam-cache.h" -#include "oscam-chk.h" -#include "oscam-client.h" -#include "oscam-config.h" -#include "oscam-ecm.h" -#include "oscam-garbage.h" -#include "oscam-failban.h" -#include "oscam-net.h" -#include "oscam-time.h" -#include "oscam-lock.h" -#include "oscam-string.h" -#include "oscam-work.h" -#include "reader-common.h" -#include "module-cccam-data.h" -#ifdef CS_CACHEEX_AIO -#include "oscam-hashtable.h" -#endif - -extern CS_MUTEX_LOCK ecmcache_lock; -extern struct ecm_request_t *ecmcwcache; -extern uint32_t ecmcwcache_size; -extern int32_t exit_oscam; - -extern CS_MUTEX_LOCK ecm_pushed_deleted_lock; -extern struct ecm_request_t *ecm_pushed_deleted; - -static pthread_mutex_t cw_process_sleep_cond_mutex; -static pthread_cond_t cw_process_sleep_cond; -static int cw_process_wakeups; -int64_t ecmc_next, cache_next, msec_wait = 3000; - -#ifdef CS_CACHEEX_AIO -// ecm-cache -typedef struct ecm_cache -{ - struct timeb first_recv_time;// time of first cw received - struct timeb upd_time; // updated time. Update time at each cw got - uint32_t csp_hash; - node ht_node; - node ll_node; -} ECM_CACHE; - -static pthread_rwlock_t ecm_cache_lock; -static hash_table ht_ecm_cache; -static list ll_ecm_cache; -static int8_t ecm_cache_init_done = 0; - -void free_ecm_cache(void) -{ - deinitialize_hash_table(&ht_ecm_cache); - pthread_rwlock_destroy(&ecm_cache_lock); -} - -void init_ecm_cache(void) -{ -#ifdef CS_CACHEEX - if(cfg.cw_cache_size > 0 || cfg.cw_cache_memory > 0) - { - init_hash_table(&ht_ecm_cache, &ll_ecm_cache); - if (pthread_rwlock_init(&ecm_cache_lock,NULL) != 0) - { cs_log("Error creating lock ecm_cache_lock!"); } - else - { ecm_cache_init_done = 1; } - } -#endif -} - -static uint8_t time_sort(ECM_CACHE *a, ECM_CACHE *b) -{ - if (((int64_t)(a->upd_time.time) * 1000ull + (int64_t) a->upd_time.millitm) == ((int64_t)(b->upd_time.time) * 1000ull + (int64_t) b->upd_time.millitm)) return 0; - return (((int64_t)(a->upd_time.time) * 1000ull + (int64_t) a->upd_time.millitm) > ((int64_t)(b->upd_time.time) * 1000ull + (int64_t) b->upd_time.millitm)) ? -1 : 1; -} - -static int compare_csp_hash_ecmcache(const void *arg, const void *obj) -{ - uint32_t h = ((const ECM_CACHE*)obj)->csp_hash; - return memcmp(arg, &h, 4); -} - -void ecm_cache_cleanup(bool force) -{ - if(!ecm_cache_init_done) - { return; } - - SAFE_RWLOCK_WRLOCK(&ecm_cache_lock); - - ECM_CACHE *ecm_cache; - node *i, *i_next; - uint32_t ll_c = 0; - uint32_t ll_ten_percent = (uint)tommy_list_count(&ll_ecm_cache)*0.1; // 10 percent of cache - - if(!force) - sort_list(&ll_ecm_cache, time_sort); - - i = get_first_node_list(&ll_ecm_cache); - while(i) - { - i_next = i->next; - - ecm_cache = get_data_from_node(i); - - if(!ecm_cache) - { - i = i_next; - continue; - } - if(!force) - { - ++ll_c; - - if(ll_c < ll_ten_percent) - { - remove_elem_list(&ll_ecm_cache, &ecm_cache->ll_node); - remove_elem_hash_table(&ht_ecm_cache, &ecm_cache->ht_node); - NULLFREE(ecm_cache); - } - else{ - break; - } - } - else{ - remove_elem_list(&ll_ecm_cache, &ecm_cache->ll_node); - remove_elem_hash_table(&ht_ecm_cache, &ecm_cache->ht_node); - NULLFREE(ecm_cache); - } - i = i_next; - } - - SAFE_RWLOCK_UNLOCK(&ecm_cache_lock); -} -#endif - -/** - * maxparallel - Helper: Calculate pending slots array size - * Formula: round(maxparallel * parallelfactor) - * parallelfactor <= 0 means no pending slots (zapping disabled) - */ -static inline int32_t get_pending_size(struct s_reader *rdr) -{ - // parallelfactor <= 0 means no pending slots (disabled or not configured) - if(rdr->parallelfactor <= 0.0f) - return 0; - int32_t size = (int32_t)(rdr->maxparallel * rdr->parallelfactor + 0.5f); - return (size < 1) ? 1 : size; -} - -/** - * maxparallel - Helper: Check if slot is expired - * Returns timeout threshold in ms, 0 if no timeout check needed - */ -static int32_t get_slot_timeout(struct s_parallel_slot *slot, int32_t paralleltimeout) -{ - if(slot->ecm_interval > 0) - return slot->ecm_interval + paralleltimeout; - else - return 10000 + paralleltimeout; // Default 10s if no interval measured -} - -/** - * maxparallel - Helper: Clear a slot - */ -static void clear_slot(struct s_parallel_slot *slot) -{ - slot->srvid = 0; - slot->ecm_interval = 0; - slot->client = NULL; - memset(&slot->last_ecm, 0, sizeof(struct timeb)); -} - -/** - * maxparallel - Helper: Add client+service to blocked list - * Replaces any existing entry for the same client - */ -static void block_client_service(struct s_reader *rdr, struct s_client *client, uint16_t srvid) -{ - if(!rdr || !client || !rdr->blocked_services) - return; - - // Check if client already has a blocked entry - if so, update it - LL_ITER it = ll_iter_create(rdr->blocked_services); - struct s_blocked_client *bc; - while((bc = ll_iter_next(&it))) - { - if(bc->client == client) - { - bc->srvid = srvid; - return; - } - } - - // Add new entry - if(!cs_malloc(&bc, sizeof(struct s_blocked_client))) - return; - bc->client = client; - bc->srvid = srvid; - ll_append(rdr->blocked_services, bc); -} - -/** - * maxparallel - Helper: Check if client+service is blocked - * Returns: 1 = blocked, 0 = not blocked - */ -static int8_t is_client_blocked(struct s_reader *rdr, struct s_client *client, uint16_t srvid) -{ - if(!rdr || !client || !rdr->blocked_services) - return 0; - - LL_ITER it = ll_iter_create(rdr->blocked_services); - struct s_blocked_client *bc; - while((bc = ll_iter_next(&it))) - { - if(bc->client == client && bc->srvid == srvid) - return 1; - } - return 0; -} - -/** - * maxparallel - Helper: Remove block for client if zapping to different service - * Only unblocks if the new service is DIFFERENT from the blocked one - */ -static void unblock_client_if_different(struct s_reader *rdr, struct s_client *client, uint16_t new_srvid) -{ - if(!rdr || !client || !rdr->blocked_services) - return; - - LL_ITER it = ll_iter_create(rdr->blocked_services); - struct s_blocked_client *bc; - while((bc = ll_iter_next(&it))) - { - if(bc->client == client) - { - // Only unblock if zapping to a DIFFERENT service - if(bc->srvid != new_srvid) - { - ll_iter_remove_data(&it); - } - return; - } - } -} - -/** - * maxparallel - Helper: Clear all blocked entries (when active slot becomes free) - */ -static void clear_blocked_services(struct s_reader *rdr) -{ - if(!rdr || !rdr->blocked_services) - return; - - ll_clear_data(rdr->blocked_services); -} - -/** - * maxparallel - Cleanup expired slots in both arrays and promote pending - * - Removes expired slots from parallel_slots (active) and parallel_slots_pending (pending) - * - Upgrades pending to active when space becomes available (FIFO) - * - Does NOT drop pending (that's done separately when active services send ECMs) - * MUST be called with parallel_lock held - * Returns: count of active slots after cleanup - */ -static int32_t reader_cleanup_slots_nolock(struct s_reader *rdr, struct timeb *now) -{ - if(!rdr || rdr->maxparallel <= 0) - return 0; - - int32_t i; - int32_t active_count = 0; - int32_t pending_count = 0; - int32_t free_active = -1; // First empty slot in active array - - // Pass 1: Clean expired slots in active array, count active - for(i = 0; i < rdr->maxparallel; i++) - { - if(rdr->parallel_slots[i].srvid == 0) - { - if(free_active < 0) - free_active = i; - continue; - } - - int64_t gone = comp_timeb(now, &rdr->parallel_slots[i].last_ecm); - int32_t timeout = get_slot_timeout(&rdr->parallel_slots[i], rdr->paralleltimeout); - - if(gone > timeout) - { - cs_log_dbg(D_READER, "reader %s: service %04X expired (no ECM for %"PRId64" ms, timeout %d ms)", - rdr->label, rdr->parallel_slots[i].srvid, gone, timeout); - clear_slot(&rdr->parallel_slots[i]); - if(free_active < 0) - free_active = i; - } - else - { - active_count++; - } - } - - // Pass 2: Clean expired slots in pending array, count active - int32_t pending_size = get_pending_size(rdr); - for(i = 0; i < pending_size; i++) - { - if(rdr->parallel_slots_prov[i].srvid == 0) - continue; - - int64_t gone = comp_timeb(now, &rdr->parallel_slots_prov[i].last_ecm); - int32_t timeout = get_slot_timeout(&rdr->parallel_slots_prov[i], rdr->paralleltimeout); - - if(gone > timeout) - { - cs_log_dbg(D_READER, "reader %s: pending service %04X expired (no ECM for %"PRId64" ms, timeout %d ms)", - rdr->label, rdr->parallel_slots_prov[i].srvid, gone, timeout); - clear_slot(&rdr->parallel_slots_prov[i]); - } - else - { - pending_count++; - } - } - - // Pass 3: Upgrade pending to active if space available (FIFO) - // This handles the zapping case: old service expired, new one can be promoted - while(active_count < rdr->maxparallel && pending_count > 0) - { - // Find oldest pending (largest age = first to arrive = FIFO upgrade) - int32_t oldest_idx = -1; - int64_t oldest_time = -1; - - for(i = 0; i < pending_size; i++) - { - if(rdr->parallel_slots_prov[i].srvid != 0) - { - int64_t age = comp_timeb(now, &rdr->parallel_slots_prov[i].last_ecm); - if(oldest_idx < 0 || age > oldest_time) - { - oldest_idx = i; - oldest_time = age; - } - } - } - - if(oldest_idx < 0) - break; - - // Find empty slot in active array - if(free_active < 0) - { - for(i = 0; i < rdr->maxparallel; i++) - { - if(rdr->parallel_slots[i].srvid == 0) - { - free_active = i; - break; - } - } - } - - if(free_active < 0) - break; // Should not happen, but safety check - - // Move pending to active - rdr->parallel_slots[free_active] = rdr->parallel_slots_prov[oldest_idx]; - clear_slot(&rdr->parallel_slots_prov[oldest_idx]); - - cs_log_dbg(D_READER, "reader %s: service %04X promoted from pending to active (slot %d)", - rdr->label, rdr->parallel_slots[free_active].srvid, free_active); - - active_count++; - pending_count--; - free_active = -1; // Need to find next empty slot - } - - // If active slots are now available, clear blocked list - // This allows previously blocked clients to try again - if(active_count < rdr->maxparallel) - { - clear_blocked_services(rdr); - } - - return active_count; -} - -/** - * maxparallel - Drop pending services when active array is full (FIFO) - * Called only when an ACTIVE service receives an ECM, proving it's still active. - * Drops the OLDEST pending first (first in, first out) - * This is fair: first to request overload is first to be denied. - * Dropped clients are added to the blocked list so they fall over to other readers. - * MUST be called with parallel_lock held - */ -static void reader_drop_pending_nolock(struct s_reader *rdr, struct timeb *now) -{ - if(!rdr || rdr->maxparallel <= 0) - return; - - // Count active and pending - int32_t i; - int32_t active_count = 0; - int32_t pending_count = 0; - int32_t pending_size = get_pending_size(rdr); - - for(i = 0; i < rdr->maxparallel; i++) - { - if(rdr->parallel_slots[i].srvid != 0) - active_count++; - } - for(i = 0; i < pending_size; i++) - { - if(rdr->parallel_slots_prov[i].srvid != 0) - pending_count++; - } - - // Drop pending if active array is full (FIFO - oldest dropped first) - while(active_count >= rdr->maxparallel && pending_count > 0) - { - // Find oldest pending (largest age = first to arrive = drop first) - int32_t oldest_idx = -1; - int64_t oldest_time = -1; - - for(i = 0; i < pending_size; i++) - { - if(rdr->parallel_slots_prov[i].srvid != 0) - { - int64_t age = comp_timeb(now, &rdr->parallel_slots_prov[i].last_ecm); - if(oldest_idx < 0 || age > oldest_time) - { - oldest_idx = i; - oldest_time = age; - } - } - } - - if(oldest_idx < 0) - break; - - // Add client to blocked list before clearing slot - struct s_parallel_slot *slot = &rdr->parallel_slots_prov[oldest_idx]; - if(slot->client) - { - block_client_service(rdr, slot->client, slot->srvid); - } - - cs_log("reader %s: dropped pending service %04X (%.3f sec old, active services still running)", - rdr->label, slot->srvid, (float)oldest_time / 1000); - clear_slot(slot); - pending_count--; - } -} - -/** - * maxparallel - Check if reader has capacity for a service (does NOT reserve slot) - * Used during ECM request to decide if reader should be tried. - * Also checks if client+service is blocked (was dropped earlier). - * Returns: 1 = has capacity (or service already registered), 0 = full or blocked (skip reader) - */ -static int8_t reader_has_capacity(struct s_reader *rdr, uint16_t srvid, struct s_client *client) -{ - if(!rdr || rdr->maxparallel <= 0) - return 1; // unlimited - - cs_readlock(__func__, &rdr->parallel_lock); - - struct timeb now; - cs_ftime(&now); - - int32_t i; - int32_t pending_size = get_pending_size(rdr); - int8_t result = 0; - - // Check if client+service is blocked (was dropped earlier) - if(is_client_blocked(rdr, client, srvid)) - { - result = 0; - goto done; - } - - // Check if service already registered in active array - for(i = 0; i < rdr->maxparallel; i++) - { - if(rdr->parallel_slots[i].srvid == srvid) - { - result = 1; - goto done; - } - } - - // Check if service already registered in pending array - for(i = 0; i < pending_size; i++) - { - if(rdr->parallel_slots_prov[i].srvid == srvid) - { - result = 1; - goto done; - } - } - - // Count active slots (with expiry check) - int32_t active_count = 0; - for(i = 0; i < rdr->maxparallel; i++) - { - if(rdr->parallel_slots[i].srvid != 0) - { - int64_t gone = comp_timeb(&now, &rdr->parallel_slots[i].last_ecm); - int32_t timeout = get_slot_timeout(&rdr->parallel_slots[i], rdr->paralleltimeout); - if(gone <= timeout) - active_count++; - } - } - - // Space in active array? - if(active_count < rdr->maxparallel) - { - result = 1; - goto done; - } - - // Space in pending array? - if(pending_size > 0) - { - int32_t pending_count = 0; - for(i = 0; i < pending_size; i++) - { - if(rdr->parallel_slots_prov[i].srvid != 0) - { - int64_t gone = comp_timeb(&now, &rdr->parallel_slots_prov[i].last_ecm); - int32_t timeout = get_slot_timeout(&rdr->parallel_slots_prov[i], rdr->paralleltimeout); - if(gone <= timeout) - pending_count++; - } - } - if(pending_count < pending_size) - { - result = 1; - goto done; - } - } - - // No capacity available - result = 0; - -done: - cs_readunlock(__func__, &rdr->parallel_lock); - return result; -} - -/** - * maxparallel - Register a service on a reader (called when CW is found) - * Uses dual-array architecture: - * - parallel_slots: active services (the limit) - * - parallel_slots_pending: pending services during zapping - * New services go to active if space available, otherwise pending. - * Returns: 1 = registered, 0 = failed - */ -static int8_t reader_register_service(struct s_reader *rdr, uint16_t srvid, struct s_client *client) -{ - if(!rdr || rdr->maxparallel <= 0) - return 1; // unlimited, always OK - - cs_writelock(__func__, &rdr->parallel_lock); - - // If client is registering a DIFFERENT service, unblock them - // (they zapped away from the blocked service) - unblock_client_if_different(rdr, client, srvid); - - struct timeb now; - cs_ftime(&now); - - // Cleanup expired slots and handle promotions/drops - int32_t active_count = reader_cleanup_slots_nolock(rdr, &now); - - int32_t i; - int32_t pending_size = get_pending_size(rdr); - - // Search for existing slot in both arrays - int32_t existing_active = -1; - int32_t existing_pending = -1; - int32_t free_active = -1; - int32_t free_pending = -1; - - // Search active array - for(i = 0; i < rdr->maxparallel; i++) - { - if(rdr->parallel_slots[i].srvid == srvid) - existing_active = i; - else if(free_active < 0 && rdr->parallel_slots[i].srvid == 0) - free_active = i; - } - - // Search pending array - for(i = 0; i < pending_size; i++) - { - if(rdr->parallel_slots_prov[i].srvid == srvid) - existing_pending = i; - else if(free_pending < 0 && rdr->parallel_slots_prov[i].srvid == 0) - free_pending = i; - } - - struct s_parallel_slot *slot = NULL; - int8_t is_new = 0; - int8_t is_pending = 0; - int32_t slot_idx = -1; - const char *array_name = "active"; - - if(existing_active >= 0) - { - // Already in active array - just update - slot = &rdr->parallel_slots[existing_active]; - slot_idx = existing_active; - is_new = 0; - } - else if(existing_pending >= 0) - { - // Already in pending array - update there - slot = &rdr->parallel_slots_prov[existing_pending]; - slot_idx = existing_pending; - is_new = 0; - is_pending = 1; - array_name = "pending"; - } - else if(active_count < rdr->maxparallel && free_active >= 0) - { - // New service, space in active array - slot = &rdr->parallel_slots[free_active]; - slot_idx = free_active; - slot->srvid = srvid; - slot->ecm_interval = 0; - slot->client = client; - is_new = 1; - } - else if(free_pending >= 0) - { - // New service, active full -> put in pending - slot = &rdr->parallel_slots_prov[free_pending]; - slot_idx = free_pending; - slot->srvid = srvid; - slot->ecm_interval = 0; - slot->client = client; - is_new = 1; - is_pending = 1; - array_name = "pending"; - } - else - { - // No slot available in either array - cs_writeunlock(__func__, &rdr->parallel_lock); - cs_log("reader %s: no slot available for service %04X (all %d+%d slots used)", - rdr->label, srvid, rdr->maxparallel, pending_size); - return 0; - } - - // Update interval for existing slots - if(!is_new && slot->last_ecm.time > 0) - { - int64_t interval = comp_timeb(&now, &slot->last_ecm); - if(interval > 0 && interval < 30000) // Sanity: < 30 seconds - { - if(slot->ecm_interval == 0) - slot->ecm_interval = (int32_t)interval; - else - slot->ecm_interval = (slot->ecm_interval + (int32_t)interval) / 2; - } - } - - slot->last_ecm = now; - - // If this is an ACTIVE service (not pending), drop pending if needed - // This ensures pending are only dropped when active services prove they're still active - if(!is_pending) - { - reader_drop_pending_nolock(rdr, &now); - } - - // Recount for logging (drop may have changed counts) - int32_t final_active = 0, final_pending = 0; - for(i = 0; i < rdr->maxparallel; i++) - { - if(rdr->parallel_slots[i].srvid != 0) - final_active++; - } - for(i = 0; i < pending_size; i++) - { - if(rdr->parallel_slots_prov[i].srvid != 0) - final_pending++; - } - - if(is_new) - { - if(final_pending > 0) - { - cs_log_dbg(D_READER, "reader %s: registered service %04X in %s slot %d (%d/%d active, +%d pending)", - rdr->label, srvid, array_name, slot_idx, final_active, rdr->maxparallel, final_pending); - } - else - { - cs_log_dbg(D_READER, "reader %s: registered service %04X in %s slot %d (%d/%d active)", - rdr->label, srvid, array_name, slot_idx, final_active, rdr->maxparallel); - } - - // Log "now full" only once per state change, and only for active services - if(!is_pending && final_active >= rdr->maxparallel && !rdr->parallel_full) - { - rdr->parallel_full = 1; - cs_log("reader %s: now full (%d/%d active)", - rdr->label, final_active, rdr->maxparallel); - } - } - - // Reset full flag when capacity becomes available - if(final_active < rdr->maxparallel && rdr->parallel_full) - { - rdr->parallel_full = 0; - cs_log_dbg(D_READER, "reader %s: capacity available (%d/%d active)", - rdr->label, final_active, rdr->maxparallel); - } - - cs_writeunlock(__func__, &rdr->parallel_lock); - return 1; -} - -void fallback_timeout(ECM_REQUEST *er) -{ - if(er->rc >= E_UNHANDLED && er->stage < 4) - { - cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} fallback timeout! (stage: %d)", (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid, er->stage); - debug_ecm(D_TRACE, "fallback for %s %s", username(er->client), buf); - while(er->stage < 4) // if preferlocalcards=1 and no answer from locals, initial stage will be 2! We need to reach stage=4 to call fallback's. - { - request_cw_from_readers(er, 0); - } - } -} - -void ecm_timeout(ECM_REQUEST *er) -{ - if(!er->readers_timeout_check) - { - er->readers_timeout_check = 1; - - if(check_client(er->client) && er->rc >= E_UNHANDLED) - { - debug_ecm(D_TRACE, "timeout for %s %s", username(er->client), buf); - - // set timeout for readers not answering - struct s_ecm_answer *ea_list; - for(ea_list = er->matching_rdr; ea_list; ea_list = ea_list->next) - { - if((ea_list->status & (REQUEST_SENT | REQUEST_ANSWERED)) == REQUEST_SENT) // Request sent, but no answer! - { - write_ecm_answer(ea_list->reader, er, E_TIMEOUT, 0, NULL, NULL, 0, NULL); // set timeout for readers not answered! - } - } - - // send timeout to client! - cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} client timeout! ", (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid); - er->rc = E_TIMEOUT; - er->rcEx = 0; - send_dcw(er->client, er); - } - } -} - -void increment_n_request(struct s_client *cl) -{ - if(check_client(cl)) - { - cl->n_request[1]++; - first_client->n_request[1]++; - } -} - -uint8_t checkCWpart(uint8_t *cw, int8_t part) -{ - uint8_t eo = part ? 8 : 0; - int8_t i; - for(i = 0; i < 8; i++) - if(cw[i + eo]) { return 1; } - return 0; -} - -void update_n_request(void) -{ - struct s_client *cl; - - cs_readlock(__func__, &clientlist_lock); - for(cl = first_client->next; cl; cl = cl->next) - { -#ifdef CS_CACHEEX - if(check_client(cl) && get_module(cl)->num != R_CSP && cl->typ == 'c' && !cl->dup && cl->account && cl->account->cacheex.mode<=1) //no cacheex 2/3 client -#else - if(check_client(cl) && get_module(cl)->num != R_CSP && cl->typ == 'c' && !cl->dup) -#endif - { - cl->n_request[0] = cl->n_request[1]; - cl->n_request[1] = 0; - } - else - { - cl->n_request[0] = 0; - cl->n_request[1] = 0; - } - } - - first_client->n_request[0] = first_client->n_request[1]; - first_client->n_request[1] = 0; - - cs_readunlock(__func__, &clientlist_lock); -} - -static void *cw_process(void) -{ - set_thread_name(__func__); - int64_t time_to_check_fbtimeout, time_to_check_ctimeout, next_check, n_request_next; - struct timeb t_now, tbc, ecmc_time, cache_time, n_request_time; - ECM_REQUEST *er = NULL; - time_t ecm_maxcachetime; - -#ifdef CS_CACHEEX - int64_t time_to_check_cacheex_wait_time; - int64_t time_to_check_cacheex_mode1_delay; -#endif - - cs_pthread_cond_init(__func__, &cw_process_sleep_cond_mutex, &cw_process_sleep_cond); - -#ifdef CS_ANTICASC - int32_t ac_next; - struct timeb ac_time; - cs_ftime(&ac_time); - add_ms_to_timeb(&ac_time, cfg.ac_stime * 60 * 1000); -#endif - - cs_ftime(&ecmc_time); - add_ms_to_timeb(&ecmc_time, 1000); - cs_ftime(&cache_time); - add_ms_to_timeb(&cache_time, 3000); - cs_ftime(&n_request_time); - add_ms_to_timeb(&n_request_time, 60 * 1000); - - while(!exit_oscam) - { - if(cw_process_wakeups == 0) // No waiting wakeups, proceed to sleep - { - sleepms_on_cond(__func__, &cw_process_sleep_cond_mutex, &cw_process_sleep_cond, msec_wait); - } - cw_process_wakeups = 0; // We've been woken up, reset the counter - if(exit_oscam) - { break; } - - next_check = 0; -#ifdef CS_ANTICASC - ac_next = 0; -#endif - ecmc_next = 0; - cache_next = 0; - msec_wait = 0; - - cs_ftime(&t_now); - cs_readlock(__func__, &ecmcache_lock); - for(er = ecmcwcache; er; er = er->next) - { - - if((er->from_cacheex || er->from_csp) // ignore ecms from cacheex/csp - || er->readers_timeout_check // ignore already checked - || !check_client(er->client)) // ignore ecm of killed clients - { - continue; - } - - if(er->rc >= E_UNHANDLED) - { -#ifdef CS_CACHEEX - // cacheex_wait_time - if(er->cacheex_wait_time && !er->cacheex_wait_time_expired) - { - tbc = er->tps; - time_to_check_cacheex_mode1_delay = 0; - time_to_check_cacheex_wait_time = add_ms_to_timeb_diff(&tbc, lb_auto_timeout(er, er->cacheex_wait_time)); - - if(comp_timeb(&t_now, &tbc) >= 0) - { - add_job(er->client, ACTION_CACHEEX_TIMEOUT, (void *)er, 0); - time_to_check_cacheex_wait_time = 0; - - } - else if(er->cacheex_mode1_delay && !er->stage && er->cacheex_reader_count>0) - { - // check for cacheex_mode1_delay - tbc = er->tps; - time_to_check_cacheex_mode1_delay = add_ms_to_timeb_diff(&tbc, lb_auto_timeout(er, er->cacheex_mode1_delay)); - - if(comp_timeb(&t_now, &tbc) >= 0) - { - add_job(er->client, ACTION_CACHEEX1_DELAY, (void *)er, 0); - time_to_check_cacheex_mode1_delay = 0; - } - } - - if(!next_check || (time_to_check_cacheex_wait_time > 0 && time_to_check_cacheex_wait_time < next_check)) - { next_check = time_to_check_cacheex_wait_time; } - - if(!next_check || (time_to_check_cacheex_mode1_delay > 0 && time_to_check_cacheex_mode1_delay < next_check)) - { next_check = time_to_check_cacheex_mode1_delay; } - } -#endif - if(er->stage < 4) - { - // fbtimeout - tbc = er->tps; - time_to_check_fbtimeout = add_ms_to_timeb_diff(&tbc, lb_auto_timeout(er, get_fallbacktimeout(er->caid))); - - if(comp_timeb(&t_now, &tbc) >= 0) - { - add_job(er->client, ACTION_FALLBACK_TIMEOUT, (void *)er, 0); - time_to_check_fbtimeout = 0; - } - - if(!next_check || (time_to_check_fbtimeout > 0 && time_to_check_fbtimeout < next_check)) - { next_check = time_to_check_fbtimeout; } - } - } - - // clienttimeout - if(!er->readers_timeout_check) // ecm stays in cache at least ctimeout+2seconds! - { - tbc = er->tps; - time_to_check_ctimeout = add_ms_to_timeb_diff(&tbc, lb_auto_timeout(er, cfg.ctimeout)); - - if(comp_timeb(&t_now, &tbc) >= 0) - { - add_job(er->client, ACTION_CLIENT_TIMEOUT, (void *)er, 0); - time_to_check_ctimeout = 0; - } - - if(!next_check || (time_to_check_ctimeout > 0 && time_to_check_ctimeout < next_check)) - { next_check = time_to_check_ctimeout; } - } - } - cs_readunlock(__func__, &ecmcache_lock); -#ifdef CS_ANTICASC - if(cfg.ac_enabled && (ac_next = comp_timeb(&ac_time, &t_now)) <= 10) - { - ac_do_stat(); - cs_ftime(&ac_time); - ac_next = add_ms_to_timeb_diff(&ac_time, cfg.ac_stime * 60 * 1000); - } -#endif - if((ecmc_next = comp_timeb(&ecmc_time, &t_now)) <= 10) - { - uint32_t count = 0; - struct ecm_request_t *ecm, *ecmt = NULL, *prv; - - cs_readlock(__func__, &ecmcache_lock); - for(ecm = ecmcwcache, prv = NULL; ecm; prv = ecm, ecm = ecm->next, count++) - { - ecm_maxcachetime = t_now.time - ((cfg.ctimeout + 500) / 1000 + 3); // to be sure no more access er! - - if(ecm->tps.time < ecm_maxcachetime) - { - cs_readunlock(__func__, &ecmcache_lock); - cs_writelock(__func__, &ecmcache_lock); - ecmt = ecm; - if(prv) - { prv->next = NULL; } - else - { ecmcwcache = NULL; } - cs_writeunlock(__func__, &ecmcache_lock); - break; - } - } - if(!ecmt) - { cs_readunlock(__func__, &ecmcache_lock); } - ecmcwcache_size = count; - - while(ecmt) - { - ecm = ecmt->next; - free_ecm(ecmt); - ecmt = ecm; - } - -#ifdef CS_CACHEEX - ecmt=NULL; - cs_readlock(__func__, &ecm_pushed_deleted_lock); - for(ecm = ecm_pushed_deleted, prv = NULL; ecm; prv = ecm, ecm = ecm->next) - { - ecm_maxcachetime = t_now.time - ((cfg.ctimeout + 500) / 1000 + 3); - if(ecm->tps.time < ecm_maxcachetime) - { - cs_readunlock(__func__, &ecm_pushed_deleted_lock); - cs_writelock(__func__, &ecm_pushed_deleted_lock); - ecmt = ecm; - if(prv) - { prv->next = NULL; } - else - { ecm_pushed_deleted = NULL; } - cs_writeunlock(__func__, &ecm_pushed_deleted_lock); - break; - } - } - if(!ecmt) - { cs_readunlock(__func__, &ecm_pushed_deleted_lock); } - - while(ecmt) - { - ecm = ecmt->next; - free_push_in_ecm(ecmt); - ecmt = ecm; - } -#endif - - cs_ftime(&ecmc_time); - ecmc_next = add_ms_to_timeb_diff(&ecmc_time, 1000); - } - - if((cache_next = comp_timeb(&cache_time, &t_now)) <= 10) - { - cleanup_cache(false); - cacheex_cleanup_hitcache(false); - - cs_ftime(&cache_time); - cache_next = add_ms_to_timeb_diff(&cache_time, 3000); - } - - if((n_request_next = comp_timeb(&n_request_time, &t_now)) <= 10) - { - update_n_request(); - cs_ftime(&n_request_time); - n_request_next = add_ms_to_timeb_diff(&n_request_time, 60 * 1000); - } - - msec_wait = next_check; -#ifdef CS_ANTICASC - if(!msec_wait || (ac_next > 0 && ac_next < msec_wait)) - { msec_wait = ac_next; } -#endif - if(!msec_wait || (ecmc_next > 0 && ecmc_next < msec_wait)) - { msec_wait = ecmc_next; } - - if(!msec_wait || (cache_next > 0 && cache_next < msec_wait)) - { msec_wait = cache_next; } - - if(!msec_wait || (n_request_next > 0 && n_request_next < msec_wait)) - { msec_wait = n_request_next; } - - if(!msec_wait) - { msec_wait = 3000; } - - cleanupcwcycle(); - } - - return NULL; -} - -void cw_process_thread_start(void) -{ - start_thread("cw_process", (void *) &cw_process, NULL, NULL, 1, 1); -} - -void cw_process_thread_wakeup(void) -{ - cw_process_wakeups++; // Do not sleep... - SAFE_COND_SIGNAL(&cw_process_sleep_cond); -} - -void convert_to_beta(struct s_client *cl, ECM_REQUEST *er, uint16_t caidto) -{ - static uint8_t headerN3[10] = { 0xc7, 0x00, 0x00, 0x00, 0x01, 0x10, 0x10, 0x00, 0x87, 0x12 }; - static uint8_t headerN2[10] = { 0xc9, 0x00, 0x00, 0x00, 0x01, 0x10, 0x10, 0x00, 0x48, 0x12 }; - - er->ocaid = er->caid; - er->caid = caidto; - er->prid = 0; - er->ecmlen = er->ecm[2] + 3; - - memmove(er->ecm + 13, er->ecm + 3, er->ecmlen - 3); - - if(er->ecmlen > 0x88) - { - memcpy(er->ecm + 3, headerN3, 10); - if(er->ecm[0] == 0x81) - { er->ecm[12] += 1; } - er->ecm[1] = 0x70; - } - else - { - memcpy(er->ecm + 3, headerN2, 10); - } - - er->ecmlen += 10; - er->ecm[2] = er->ecmlen - 3; - er->btun = 1; - - cl->cwtun++; - cl->account->cwtun++; - first_client->cwtun++; - - cs_log_dbg(D_TRACE, "ECM converted ocaid from 0x%04X to BetaCrypt caid 0x%04X for service id 0x%04X", - er->ocaid, caidto, er->srvid); -} - -void convert_to_nagra(struct s_client *cl, ECM_REQUEST *er, uint16_t caidto) -{ - cs_log_dbg(D_TRACE, "convert_to_nagra"); - er->ocaid = er->caid; - er->caid = caidto; - er->prid = 0; - er->ecmlen = er->ecm[2] + 3; - - // not sure - if(er->ecmlen < 0x52) - { er->ecm[1] = 0x30; } - - memmove(er->ecm + 3, er->ecm + 13, er->ecmlen - 3); - - er->ecmlen -= 10; - er->ecm[2] = er->ecmlen - 3; - er->btun = 1; - - cl->cwtun++; - cl->account->cwtun++; - first_client->cwtun++; - - cs_log_dbg(D_TRACE, "ECM converted ocaid from: 0x%04X to Nagra: 0x04%X for service id:0x04%X", - er->ocaid, caidto, er->srvid); -} - -void cs_betatunnel(ECM_REQUEST *er) -{ - int32_t i; - struct s_client *cl = cur_client(); - uint32_t mask_all = 0xFFFF; - TUNTAB *ttab = &cl->ttab; - - for(i = 0; i < ttab->ttnum; i++) - { - if((er->caid == ttab->ttdata[i].bt_caidfrom) && ((er->srvid == ttab->ttdata[i].bt_srvid) || (ttab->ttdata[i].bt_srvid) == mask_all)) - { - if(chk_is_betatunnel_caid(er->caid) == 1 && er->ocaid == 0x0000) - { - convert_to_nagra(cl, er, ttab->ttdata[i].bt_caidto); - } - else if(er->ocaid == 0x0000) - { - convert_to_beta(cl, er, ttab->ttdata[i].bt_caidto); - } - return; - } - } -} - -static void remove_ecm_from_reader(ECM_REQUEST *ecm) -{ - int32_t i; - struct s_ecm_answer *ea = ecm->matching_rdr; - while(ea) - { - if((ea->status & REQUEST_SENT) && !(ea->status & REQUEST_ANSWERED)) - { - // we found a outstanding reader, clean it: - struct s_reader *rdr = ea->reader; - if(rdr) - { - struct s_client *cl = rdr->client; - if(check_client(cl)) - { - ECM_REQUEST *ecmtask = cl->ecmtask; - if(ecmtask) - { - for(i = 0; i < cfg.max_pending; ++i) - { - if(ecmtask[i].parent == ecm) - { - ecmtask[i].client = NULL; - cacheex_set_csp_lastnode(&ecmtask[i]); - } - } - } - } - } - } - ea = ea->next; - } -} - -void free_ecm(ECM_REQUEST *ecm) -{ - struct s_ecm_answer *ea, *nxt; - cacheex_free_csp_lastnodes(ecm); - gbox_free_cards_pending(ecm); - // remove this ecm from reader queue to avoid segfault on very late answers (when ecm is already disposed) - // first check for outstanding answers: - remove_ecm_from_reader(ecm); - // free matching_rdr list: - ea = ecm->matching_rdr; - ecm->matching_rdr = NULL; - while(ea) - { - nxt = ea->next; - cs_lock_destroy(__func__, &ea->ecmanswer_lock); - add_garbage(ea); - ea = nxt; - } - if(ecm->src_data) - { add_garbage(ecm->src_data); } - add_garbage(ecm); -} - - -void free_push_in_ecm(ECM_REQUEST *ecm) -{ - cacheex_free_csp_lastnodes(ecm); - gbox_free_cards_pending(ecm); - if(ecm->src_data) - { NULLFREE(ecm->src_data); } - NULLFREE(ecm); -} - -ECM_REQUEST *get_ecmtask(void) -{ - ECM_REQUEST *er = NULL; - struct s_client *cl = cur_client(); - if(!cl) - { return NULL; } - if(!cs_malloc(&er, sizeof(ECM_REQUEST))) - { return NULL; } - cs_ftime(&er->tps); - er->rc = E_UNHANDLED; - er->client = cl; - er->grp = 0; // no readers/cacheex-clients answers yet - //cs_log("client %s ECMTASK %d module %s", username(cl), n, get_module(cl)->desc); - return er; -} - -void cleanup_ecmtasks(struct s_client *cl) -{ - if(!cl) { return; } - - ECM_REQUEST *ecm; - - // remove this clients ecm from queue. because of cache, just null the client: - cs_readlock(__func__, &ecmcache_lock); - for(ecm = ecmcwcache; ecm && cl; ecm = ecm->next) - { - if(ecm->client == cl) - { - ecm->client = NULL; - } - } - cs_readunlock(__func__, &ecmcache_lock); - - // remove client from rdr ecm-queue: - cs_readlock(__func__, &readerlist_lock); - struct s_reader *rdr = first_active_reader; - while(rdr) - { - if(check_client(rdr->client) && rdr->client->ecmtask) - { - int i; - for(i = 0; (i < cfg.max_pending) && cl; i++) - { - ecm = &rdr->client->ecmtask[i]; - if(ecm->client == cl) - { - ecm->client = NULL; - } - } - } - rdr = rdr->next; - } - cs_readunlock(__func__, &readerlist_lock); - -} - -static void add_cascade_data(struct s_client *client, ECM_REQUEST *er) -{ - if(!client->cascadeusers) - { client->cascadeusers = ll_create("cascade_data"); } - LLIST *l = client->cascadeusers; - LL_ITER it = ll_iter_create(l); - time_t now = time(NULL); - struct s_cascadeuser *cu; - int8_t found = 0; - while((cu = ll_iter_next(&it))) - { - if(er->caid == cu->caid && er->prid == cu->prid && er->srvid == cu->srvid) // found it - { - if(cu->time < now) - { cu->cwrate = now - cu->time; } - cu->time = now; - found = 1; - } - else if(cu->time + 60 < now) // old - { ll_iter_remove_data(&it); } - } - - if(!found) // add it if not found - { - if(!cs_malloc(&cu, sizeof(struct s_cascadeuser))) - { return; } - cu->caid = er->caid; - cu->prid = er->prid; - cu->srvid = er->srvid; - cu->time = now; - ll_append(l, cu); - } -} - -int32_t is_double_check_caid(ECM_REQUEST *er, FTAB *double_check_caid) -{ - if(!double_check_caid->nfilts) { return 1; } - - int32_t i, k; - for(i = 0; i < double_check_caid->nfilts; i++) - { - uint16_t tcaid = double_check_caid->filts[i].caid; - if(tcaid && (tcaid == er->caid || (tcaid < 0x0100 && (er->caid >> 8) == tcaid))) // caid match - { - int32_t nprids = double_check_caid->filts[i].nprids; - if(!nprids) // No Provider ->Ok - { return 1; } - - for(k = 0; k < nprids; k++) - { - uint32_t prid = double_check_caid->filts[i].prids[k]; - if(prid == er->prid) // Provider matches - { return 1; } - } - } - } - - return 0; -} - -struct s_ecm_answer *get_ecm_answer(struct s_reader *reader, ECM_REQUEST *er) -{ - if(!er || !reader) { return NULL; } - - struct s_ecm_answer *ea; - - for(ea = er->matching_rdr; ea; ea = ea->next) - { - if(ea->reader == reader) - { - return ea; - } - } - return NULL; -} - -void distribute_ea(struct s_ecm_answer *ea) -{ - struct s_ecm_answer *ea_temp; - - for(ea_temp = ea->pending; ea_temp; ea_temp = ea_temp->pending_next) - { - cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} [distribute_ea] send ea (%s) by reader %s answering for client %s", (check_client(ea_temp->er->client) ? ea_temp->er->client->account->usr : "-"), ea_temp->er->caid, ea_temp->er->prid, ea_temp->er->srvid, ea->rc==E_FOUND?"OK":"NOK", ea_temp->reader->label, (check_client(ea->er->client) ? ea->er->client->account->usr : "-")); -#ifdef CS_CACHEEX_AIO - if(ea->rc==E_FOUND && ea->er->localgenerated) - ea_temp->er->localgenerated = 1; -#endif - // e.g. we cannot send timeout, because "ea_temp->er->client" could wait/ask other readers! Simply set not_found if different from E_FOUND! - write_ecm_answer(ea_temp->reader, ea_temp->er, (ea->rc==E_FOUND? E_FOUND : E_NOTFOUND), ea->rcEx, ea->cw, NULL, ea->tier, &ea->cw_ex); - } -} - -int32_t send_dcw(struct s_client *client, ECM_REQUEST *er) -{ - if(!check_client(client) || client->typ != 'c') - { return 0; } - - cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} [send_dcw] rc %d from reader %s", (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid, er->rc, er->selected_reader ? er->selected_reader->label : "-"); - - static const char stageTxt[] = { '0', 'C', 'L', 'P', 'F', 'X' }; - static const char *stxt[] = { "found", "cache1", "cache2", "cache3", "not found", "timeout", "sleeping", - "fake", "invalid", "corrupt", "no card", "expdate", "disabled", "stopped" }; - - static const char *stxtEx[16] = {"", "group", "caid", "ident", "class", "chid", "queue", "peer", "sid", "", "", "", "", "", "", ""}; - static const char *stxtWh[16] = {"", "user ", "reader ", "server ", "lserver ", "", "", "", "", "", "", "", "" , "" , "", ""}; -#ifdef CS_CACHEEX_AIO - char sby[100] = "", sreason[100] = "", scwcinfo[32] = "", schaninfo[CS_SERVICENAME_SIZE] = "", srealecmtime[50]=""; -#else - char sby[100] = "", sreason[70] = "", scwcinfo[32] = "", schaninfo[CS_SERVICENAME_SIZE] = "", srealecmtime[50]=""; -#endif - char erEx[32] = ""; - char usrname[38] = ""; - char channame[28]; - struct timeb tpe; - - snprintf(usrname, sizeof(usrname) - 1, "%s", username(client)); - -#ifdef WITH_DEBUG - if(cs_dblevel & D_CLIENTECM) - { - char buf[ECM_FMT_LEN]; - char ecmd5[17 * 3]; - char cwstr[17 * 3]; - format_ecm(er, buf, ECM_FMT_LEN); - cs_hexdump(0, er->ecmd5, 16, ecmd5, sizeof(ecmd5)); - cs_hexdump(0, er->cw, 16, cwstr, sizeof(cwstr)); -#ifdef CS_CACHEEX - char csphash[5 * 3]; - cs_hexdump(0, (void *)&er->csp_hash, 4, csphash, sizeof(csphash)); - cs_log_dbg(D_CLIENTECM, "Client %s csphash %s cw %s rc %d %s", username(client), csphash, cwstr, er->rc, buf); -#else - cs_log_dbg(D_CLIENTECM, "Client %s cw %s rc %d %s", username(client), cwstr, er->rc, buf); -#endif - } -#endif - - struct s_reader *er_reader = er->selected_reader; // responding reader - struct s_ecm_answer *ea_orig = get_ecm_answer(er_reader, er); - - - // check if ecm_answer from pending's - if(ea_orig && ea_orig->is_pending && er->rc == E_FOUND) - { er->rc = E_CACHE2; } - - - // check if answer from cacheex-1 reader - if(er->rc == E_FOUND && er_reader && cacheex_reader(er_reader)) // so add hit to cacheex mode 1 readers - { - er->rc = E_CACHEEX; - } - - // real ecm time - if(ea_orig && !ea_orig->is_pending && er->rc == E_FOUND - && ( -#ifdef CS_CACHEEX - er->cacheex_wait_time || -#endif - (ea_orig->status & READER_FALLBACK))) - { - snprintf(srealecmtime, sizeof(srealecmtime) - 1, " (real %d ms)", ea_orig->ecm_time); - } - - - if(er->rc == E_TIMEOUT) - { -#ifdef CS_CACHEEX - if(!er->from_cacheex1_client) // cosmetic: show "by" readers only for "normal" clients - { -#endif - struct s_ecm_answer *ea_list; - int32_t ofs = 0; - - for(ea_list = er->matching_rdr; ea_list; ea_list = ea_list->next) - { - if(ea_list->reader && ofs < (int32_t)sizeof(sby) && ((ea_list->status & REQUEST_SENT) && (ea_list->rc == E_TIMEOUT || ea_list->rc >= E_99))) //Request send, but no cw answered! - { - ofs += snprintf(sby + ofs, sizeof(sby) - ofs - 1, "%s%s", ofs ? "," : " by ", ea_list->reader->label); - } - } - - if(er->ocaid && ofs < (int32_t)sizeof(sby)) - { snprintf(sby + ofs, sizeof(sby) - ofs - 1, "(btun %04X)", er->ocaid); } - -#ifdef CS_CACHEEX - } -#endif - } - else if(er_reader) - { - // add marker to reader if ECM_REQUEST was betatunneled - if(er->ocaid) - { snprintf(sby, sizeof(sby) - 1, " by %s(btun %04X)", er_reader->label, er->ocaid); } - else - { snprintf(sby, sizeof(sby) - 1, " by %s", er_reader->label); } - } -#ifdef CS_CACHEEX - else if(er->cacheex_src) // only for cacheex mode-3 clients (no mode-1 or mode-2 because reader is set!) and csp - { - char *cex_name = "-"; - if(check_client(er->cacheex_src) && er->cacheex_src->account) - { - if(er->cacheex_src->account->usr[0] != '\0') - cex_name = er->cacheex_src->account->usr; - else - cex_name = "csp"; - } - - if(er->ocaid) - { - snprintf(sby, sizeof(sby) - 1, " by %s(btun %04X)", cex_name, er->ocaid); - } - else - { - snprintf(sby, sizeof(sby) - 1, " by %s", cex_name); - } - } -#endif - - if(er->rc < E_NOTFOUND) - { - er->rcEx = 0; - // memset(er->msglog, 0, MSGLOGSIZE); // remove reader msglog from previous requests that failed, founds never give back msglog! - } - - if(er->rcEx) - { snprintf(erEx, sizeof(erEx) - 1, "rejected %s%s", stxtWh[er->rcEx >> 4], stxtEx[er->rcEx & 0xf]); } - - get_servicename_or_null(client, er->srvid, er->prid, er->caid, channame, sizeof(channame)); - if(!channame[0]) - { - schaninfo[0] = '\0'; - } - else - { - snprintf(schaninfo, sizeof(schaninfo) - 1, " - %s", channame); - } - -#ifdef CS_CACHEEX - int cx = 0; - if(er->msglog[0]) - { - cx = snprintf(sreason, sizeof(sreason) - 1, " (%s)", er->msglog); - } -#else - if(er->msglog[0]) - { - snprintf(sreason, sizeof(sreason) - 1, " (%s)", er->msglog); - } -#endif -#ifdef CW_CYCLE_CHECK - if(er->cwc_msg_log[0]) - { snprintf(scwcinfo, sizeof(scwcinfo) - 1, " (%.26s)", er->cwc_msg_log); } -#endif - - cs_ftime(&tpe); - -#ifdef CS_CACHEEX - int cx2 = 0; - if(er->rc >= E_CACHEEX && er->cacheex_wait_time && er->cacheex_wait_time_expired) - { - cx2 = snprintf(sreason+cx, (sizeof sreason)-cx, " (wait_time over)"); - } - else - { - cx2 = cx; - } - - if(er->cw_count>1) - { -#ifdef CS_CACHEEX_AIO - if(er->cw_count > 0x0F000000 || er->localgenerated) - { - uint32_t cw_count_cleaned = er->cw_count ^ 0x0F000000; - if(cw_count_cleaned > 1) - snprintf(sreason+cx2, (sizeof sreason)-cx2, " (cw count %d) (lg)", cw_count_cleaned); - else - snprintf(sreason+cx2, (sizeof sreason)-cx2, " (lg)"); - } - else - { -#endif - - snprintf (sreason+cx2, (sizeof sreason)-cx2, " (cw count %d)", er->cw_count); - -#ifdef CS_CACHEEX_AIO - } - - } - else - { - if(er->localgenerated) - snprintf(sreason+cx2, (sizeof sreason)-cx2, " (lg)"); -#endif - } - -#endif - - client->cwlastresptime = comp_timeb(&tpe, &er->tps); - - time_t now = time(NULL); - webif_client_add_lastresponsetime(client, client->cwlastresptime, now, er->rc); // add to ringbuffer - - if(er_reader) - { - struct s_client *er_cl = er_reader->client; - if(check_client(er_cl)) - { - er_cl->cwlastresptime = client->cwlastresptime; - webif_client_add_lastresponsetime(er_cl, client->cwlastresptime, now, er->rc); - er_cl->last_providptr = client->last_providptr; - er_cl->last_srvidptr = client->last_srvidptr; - } - } - - webif_client_init_lastreader(client, er, er_reader, stxt); - - client->last = now; - - //cs_log_dbg(D_TRACE, "CHECK rc=%d er->cacheex_src=%s", er->rc, username(er->cacheex_src)); - switch(er->rc) - { - case E_FOUND: - { - client->cwfound++; - client->account->cwfound++; - first_client->cwfound++; - break; - } - case E_CACHE1: - case E_CACHE2: - case E_CACHEEX: - { - client->cwcache++; - client->account->cwcache++; - first_client->cwcache++; -#ifdef CS_CACHEEX - if(check_client(er->cacheex_src)) - { - first_client->cwcacheexhit++; - er->cacheex_src->cwcacheexhit++; - if(er->cacheex_src->account) - { er->cacheex_src->account->cwcacheexhit++; } - } -#endif - break; - } - case E_NOTFOUND: - case E_CORRUPT: - case E_NOCARD: - { - if(er->rcEx) - { - client->cwignored++; - client->account->cwignored++; - first_client->cwignored++; - } - else - { - client->cwnot++; - client->account->cwnot++; - first_client->cwnot++; - } - break; - } - case E_TIMEOUT: - { - client->cwtout++; - client->account->cwtout++; - first_client->cwtout++; - break; - } - default: - { - client->cwignored++; - client->account->cwignored++; - first_client->cwignored++; - } - } - -#ifdef CS_ANTICASC -// [zaplist] ACoSC anticascading - if(cfg.acosc_enabled) - { - int8_t max_active_sids = 0; - int8_t zap_limit = 0; - int8_t penalty = 0; - int32_t penalty_duration = 0; - int32_t delay = 0; - int8_t max_ecms_per_minute = 0; - char *info1 = NULL; - char *info2 = NULL; - char *info3 = NULL; - char *info4 = NULL; - char *info5 = NULL; - char *info6 = NULL; - - // **global or user value? - cs_writelock(__func__, &clientlist_lock); - - max_active_sids = client->account->acosc_max_active_sids == -1 ? cfg.acosc_max_active_sids : client->account->acosc_max_active_sids; - info1 = client->account->acosc_max_active_sids == -1 ? "Globalvalue" : "Uservalue"; - - zap_limit = client->account->acosc_zap_limit == -1 ? cfg.acosc_zap_limit : client->account->acosc_zap_limit; - info5 = client->account->acosc_zap_limit == -1 ? "Globalvalue" : "Uservalue"; - - penalty = client->account->acosc_penalty == -1 ? cfg.acosc_penalty : client->account->acosc_penalty; - info2 = client->account->acosc_penalty == -1 ? "Globalvalue" : "Uservalue"; - - penalty_duration = client->account->acosc_penalty_duration == -1 ? cfg.acosc_penalty_duration : client->account->acosc_penalty_duration; - info3 = client->account->acosc_penalty_duration == -1 ? "Globalvalue" : "Uservalue"; - - delay = client->account->acosc_delay == -1 ? cfg.acosc_delay : client->account->acosc_delay; - info4 = client->account->acosc_delay == -1 ? "Globalvalue" : "Uservalue"; - - max_ecms_per_minute = client->account->acosc_max_ecms_per_minute == -1 ? cfg.acosc_max_ecms_per_minute : client->account->acosc_max_ecms_per_minute; - info6 = client->account->acosc_max_ecms_per_minute == -1 ? "Globalvalue" : "Uservalue"; - - //** - - if((er->rc < E_NOTFOUND && max_active_sids > 0) || zap_limit > 0 || max_ecms_per_minute > 0) - { - int8_t k = 0; - int8_t active_sid_count = 0; - time_t zaptime = time(NULL); - - if(client->account->acosc_penalty_active == 4 && client->account->acosc_penalty_until <= zaptime) // reset penalty_active - { - client->account->acosc_penalty_active = 0; - client->account->acosc_penalty_until = 0; - } - - if(client->account->acosc_penalty_active == 0 && max_active_sids > 0) - { - for(k=0; k<15 ; k++) - { - if(zaptime-30 < client->client_zap_list[k].lasttime && client->client_zap_list[k].request_stage == 10) - { - cs_log_dbg(D_TRACE, "[zaplist] ACoSC for Client: %s more then 10 ECM's for %04X@%06X/%04X/%04X", username(client), client->client_zap_list[k].caid, client->client_zap_list[k].provid, client->client_zap_list[k].chid, client->client_zap_list[k].sid); - active_sid_count ++; - } - } - cs_log_dbg(D_TRACE, "[zaplist] ACoSC for Client: %s active_sid_count= %i with more than 10 followed ECM's (mas:%i (%s))", username(client), active_sid_count, max_active_sids, info1); - } - - if(client->account->acosc_penalty_active == 0 && max_active_sids > 0 && active_sid_count > max_active_sids) //max_active_sids reached - { - client->account->acosc_penalty_active = 1; - client->account->acosc_penalty_until = zaptime + penalty_duration; - } - - if(client->account->acosc_penalty_active == 0 && zap_limit > 0 && client->account->acosc_user_zap_count > zap_limit) // zap_limit reached - { - client->account->acosc_penalty_active = 2; - client->account->acosc_penalty_until = zaptime + penalty_duration; - } - - if(client->account->acosc_penalty_active == 0 && max_ecms_per_minute > 0 && client->n_request[1] >= max_ecms_per_minute && penalty != 4) // max ecms per minute reached - { - client->account->acosc_penalty_active = 3; - client->account->acosc_penalty_until = zaptime + penalty_duration; - } - - if(client->account->acosc_penalty_active == 0 && max_ecms_per_minute > 0 && client->n_request[1] > 0 && penalty == 4) // max ecms per minute with hidecards penalty - { - client->account->acosc_penalty_active = 3; - client->account->acosc_penalty_until = zaptime + penalty_duration; - } - - if(client->account->acosc_penalty_active > 0) - { - if(client->account->acosc_penalty_active == 4) - { cs_log_dbg(D_TRACE, "[zaplist] ACoSC for Client: %s penalty_duration: %" PRId64 " seconds left(%s)", username(client), (int64_t)(client->account->acosc_penalty_until - zaptime), info3); } - - int16_t lt = get_module(client)->listenertype; - switch(penalty) - { - case 1: // NULL CW - er->rc = E_FAKE; // E_FAKE give only a status fake not a NULL cw - er->rcEx = E2_WRONG_CHKSUM; - if(client->account->acosc_penalty_active == 1) - { cs_log("[zaplist] ACoSC for Client: %s max_activ_sids reached: %i:%i(%s) penalty: 1(%s) send null CW", username(client), active_sid_count, max_active_sids, info1, info2); } - if(client->account->acosc_penalty_active == 2) - { cs_log("[zaplist] ACoSC for Client: %s zap_limit reached: %i:%i(%s) penalty: 1(%s) send null CW", username(client), client->account->acosc_user_zap_count, zap_limit, info5, info2); } - if(client->account->acosc_penalty_active == 3) - { cs_log("[maxecms] ACoSC for Client: %s max_ecms_per_minute reached: ecms_last_minute=%i ecms_now=%i max=%i(%s) penalty: 1(%s) send null CW", username(client), client->n_request[0], client->n_request[1], max_ecms_per_minute, info6, info2); } - break; - - case 2: // ban - if(lt != LIS_DVBAPI) - { - if(client->account->acosc_penalty_active == 1) - { cs_log("[zaplist] ACoSC for Client: %s max_activ_sids reached: %i:%i(%s) penalty: 2(%s) BAN Client - Kill and set Client to failban list for %i sec.", username(client), active_sid_count, max_active_sids, info1, info2, penalty_duration); } - if(client->account->acosc_penalty_active == 2) - { cs_log("[zaplist] ACoSC for Client: %s zap_limit reached: %i:%i(%s) penalty: 2(%s) BAN Client - Kill and set Client to failban list for %i sec.", username(client), client->account->acosc_user_zap_count, zap_limit, info5, info2, penalty_duration); } - if(client->account->acosc_penalty_active == 3) - { cs_log("[maxecms] ACoSC for Client: %s max_ecms_per_minute reached: ecms_last_minute=%i ecms_now=%i max=%i(%s) penalty: 2(%s) BAN Client - Kill and set Client to failban list for %i sec.", username(client), client->n_request[0], client->n_request[1], max_ecms_per_minute, info6, info2, penalty_duration); } - cs_add_violation_acosc(client, client->account->usr, penalty_duration); - add_job(client, ACTION_CLIENT_KILL, NULL, 0); - } - else - { - cs_log("[zaplist] ACoSC for Client: %s %i:%i(%s) penalty: 2(%s) BAN Client - don't Ban dvbapi user only stop decoding", username(client), active_sid_count, max_active_sids, info1, info2); - } - er->rc = E_DISABLED; - break; - - case 3: // delay - if(client->account->acosc_penalty_active == 1) - { cs_log("[zaplist] ACoSC for Client: %s max_activ_sids reached: %i:%i(%s) penalty: 3(%s) delay CW: %ims(%s)", username(client), active_sid_count, max_active_sids, info1, info2, delay, info4); } - if(client->account->acosc_penalty_active == 2) - { cs_log("[zaplist] ACoSC for Client: %s zap_limit reached: %i:%i(%s) penalty: 3(%s) delay CW: %ims(%s)", username(client), client->account->acosc_user_zap_count, zap_limit, info5, info2, delay, info4); } - if(client->account->acosc_penalty_active == 3) - { cs_log("[maxecms] ACoSC for Client: %s max_ecms_per_minute reached: ecms_last_minute=%i ecms_now=%i max=%i(%s) penalty: 3(%s) delay CW: %ims(%s)", username(client), client->n_request[0], client->n_request[1], max_ecms_per_minute, info6, info2, delay, info4); } - cs_writeunlock(__func__, &clientlist_lock); - cs_sleepms(delay); - cs_writelock(__func__, &clientlist_lock); - client->cwlastresptime += delay; - snprintf(sreason, sizeof(sreason)-1, " (%d ms penalty delay)", delay); - break; - case 4: // hidecards - if(client->account->acosc_penalty_active == 3) - { - cs_log("[maxecms] ACoSC for Client: %s ecms_last_minute=%i ecms_now=%i max=%i(%s) penalty: 4(%s) hidecards - hidecards to the client for %i sec", username(client), client->n_request[0], client->n_request[1], max_ecms_per_minute, info6, info2, penalty_duration); - client->start_hidecards = 1; - } - break; - default: // logging - if(client->account->acosc_penalty_active == 1) - { cs_log("[zaplist] ACoSC for Client: %s max_activ_sids reached: %i:%i(%s) penalty: 0(%s) only logging", username(client), active_sid_count, max_active_sids, info1, info2); } - if(client->account->acosc_penalty_active == 2) - { cs_log("[zaplist] ACoSC for Client: %s zap_limit reached: %i:%i(%s) penalty: 0(%s) only logging", username(client), client->account->acosc_user_zap_count, zap_limit, info5, info2); } - if(client->account->acosc_penalty_active == 3) - { cs_log("[maxecms] ACoSC for Client: %s max_ecms_per_minute reached: ecms_last_minute=%i ecms_now=%i max=%i(%s) penalty: 0(%s) only logging", username(client), client->n_request[0], client->n_request[1], max_ecms_per_minute, info6, info2); } - break; - } - client->account->acosc_user_zap_count = 0; // we got already a penalty - client->account->acosc_penalty_active = 3; - client->account->acosc_penalty_active = 4; - } - } - cs_writeunlock(__func__, &clientlist_lock); - } -#endif - - if(cfg.double_check && er->rc <= E_CACHE2 && er->selected_reader && is_double_check_caid(er, &cfg.double_check_caid)) - { - if(er->checked == 0) // First CW, save it and wait for next one - { - er->checked = 1; - er->origin_reader = er->selected_reader; - memcpy(er->cw_checked, er->cw, sizeof(er->cw)); - cs_log("DOUBLE CHECK FIRST CW by %s idx %d cpti %d", er->origin_reader->label, er->idx, er->msgid); - } - else if(er->origin_reader != er->selected_reader) // Second (or third and so on) cw. We have to compare - { - if(memcmp(er->cw_checked, er->cw, sizeof(er->cw)) == 0) - { - er->checked++; - cs_log("DOUBLE CHECKED! %d. CW by %s idx %d cpti %d", er->checked, er->selected_reader->label, er->idx, er->msgid); - } - else - { - cs_log("DOUBLE CHECKED NONMATCHING! %d. CW by %s idx %d cpti %d", er->checked, er->selected_reader->label, er->idx, er->msgid); - } - } - if(er->checked < 2) // less as two same cw? mark as pending! - { - er->rc = E_UNHANDLED; - goto ESC; - } - } - - ac_chk(client, er, 1); - int32_t is_fake = 0; - if(er->rc == E_FAKE) - { - is_fake = 1; - er->rc = E_FOUND; - } - - get_module(client)->send_dcw(client, er); - - add_cascade_data(client, er); - - if(is_fake) - { er->rc = E_FAKE; } - -#ifdef CS_ANTICASC - cs_writelock(__func__, &clientlist_lock); - if(client->start_hidecards) - { - client->start_hidecards = 0; - add_job(client, ACTION_CLIENT_HIDECARDS, NULL, 0); - } - cs_writeunlock(__func__, &clientlist_lock); -#endif - - if(!(er->rc == E_SLEEPING && client->cwlastresptime == 0)) - { - char buf[ECM_FMT_LEN]; - format_ecm(er, buf, ECM_FMT_LEN); - if(er->reader_avail == 1 || er->stage == 0) - { - cs_log("%s (%s): %s (%d ms)%s%s%s%s", usrname, buf, er->rcEx ? erEx : stxt[er->rc], - client->cwlastresptime, sby, schaninfo, sreason, scwcinfo); - } - else - { - cs_log("%s (%s): %s (%d ms)%s (%c/%d/%d/%d)%s%s%s%s", usrname, buf, er->rcEx ? erEx : stxt[er->rc], - client->cwlastresptime, sby, stageTxt[er->stage], er->reader_requested, - (er->reader_count + er->fallback_reader_count), er->reader_avail, schaninfo, - srealecmtime, sreason, scwcinfo); - } - } - - cs_log_dump_dbg(D_ATR, er->cw, 16, "cw:"); - led_status_cw_not_found(er); - -ESC: - - return 0; -} - -/* - * write_ecm_request(): - */ -static int32_t write_ecm_request(struct s_reader *rdr, ECM_REQUEST *er) -{ - add_job(rdr->client, ACTION_READER_ECM_REQUEST, (void *)er, 0); - return 1; -} - -/** - * sends the ecm request to the readers - * ECM_REQUEST er : the ecm - * er->stage: 0 = no reader asked yet - * 2 = ask only local reader (skipped without preferlocalcards) - * 3 = ask any non fallback reader - * 4 = ask fallback reader - **/ -void request_cw_from_readers(ECM_REQUEST *er, uint8_t stop_stage) -{ - struct s_ecm_answer *ea; - int8_t sent = 0; - - if(er->stage >= 4) { return; } - - while(1) - { - if(stop_stage && er->stage >= stop_stage) { return; } - - er->stage++; - -#ifdef CS_CACHEEX - if(er->stage == 1 && er->preferlocalcards==2) - { er->stage++; } -#else - if(er->stage == 1) - { er->stage++; } -#endif - - if(er->stage == 2 && !er->preferlocalcards) - { er->stage++; } - - for(ea = er->matching_rdr; ea; ea = ea->next) - { - switch(er->stage) - { -#ifdef CS_CACHEEX - case 1: - { - // Cache-Exchange - if((ea->status & REQUEST_SENT) || - (ea->status & (READER_CACHEEX | READER_ACTIVE)) != (READER_CACHEEX | READER_ACTIVE)) - { continue; } - break; - } -#endif - case 2: - { - // only local reader - if((ea->status & REQUEST_SENT) || - (ea->status & (READER_ACTIVE | READER_FALLBACK | READER_LOCAL)) != (READER_ACTIVE | READER_LOCAL)) - { continue; } - break; - } - case 3: - { - // any non fallback reader not asked yet - if((ea->status & REQUEST_SENT) || - (ea->status & (READER_ACTIVE | READER_FALLBACK)) != READER_ACTIVE) - { continue; } - break; - } - default: - { - // only fallbacks - if((ea->status & REQUEST_SENT) || - (ea->status & (READER_ACTIVE | READER_FALLBACK)) != (READER_ACTIVE | READER_FALLBACK)) - { continue; } - break; - } - } - - struct s_reader *rdr = ea->reader; -#ifdef WITH_DEBUG - if (cs_dblevel & (D_TRACE | D_CSP)) - { - char ecmd5[17 * 3]; - cs_hexdump(0, er->ecmd5, 16, ecmd5, sizeof(ecmd5)); - cs_log_dbg(D_TRACE | D_CSP, "request_cw stage=%d to reader %s ecm hash=%s", er->stage, rdr ? rdr->label : "", ecmd5); - } -#endif - // maxparallel: check if reader has capacity (slot is reserved later when CW found) - if(rdr->maxparallel > 0 && !reader_has_capacity(rdr, er->srvid, er->client)) - { - cs_log_dbg(D_LB, "reader %s skipped for %s srvid %04X (maxparallel %d reached)", - rdr->label, check_client(er->client) ? er->client->account->usr : "-", - er->srvid, rdr->maxparallel); - continue; - } - - ea->status |= REQUEST_SENT; - cs_ftime(&ea->time_request_sent); - - er->reader_requested++; - - write_ecm_request(ea->reader, er); - - // set sent=1 only if reader is active/connected. If not, switch to next stage! - if(!sent && rdr) - { - struct s_client *rcl = rdr->client; - if(check_client(rcl)) - { - if(rcl->typ == 'r' && rdr->card_status == CARD_INSERTED) - { sent = 1; } - else if(rcl->typ == 'p' && (rdr->card_status == CARD_INSERTED || rdr->tcp_connected)) - { sent = 1; } - } - } - - cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} [write_ecm_request] reader %s --> SENT %d", (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid, rdr ? ea->reader->label : "-", sent); - } - - if(sent || er->stage >= 4) - { break; } - } -} - -void add_cache_from_reader(ECM_REQUEST *er, struct s_reader *rdr, uint32_t csp_hash, uint8_t *ecmd5, uint8_t *cw, int16_t caid, int32_t prid, int16_t srvid -#ifdef CS_CACHEEX_AIO - , int32_t ecm_time -#endif -) -{ - ECM_REQUEST *ecm; - if (cs_malloc(&ecm, sizeof(ECM_REQUEST))) - { - cs_ftime(&ecm->tps); - - ecm->cwc_cycletime = er->cwc_cycletime; - ecm->cwc_next_cw_cycle = er->cwc_next_cw_cycle; - memcpy(ecm->ecm, er->ecm, sizeof(ecm->ecm)); // ecm[0] is pushed to cacheexclients so we need a copy from it - ecm->caid = caid; - ecm->prid = prid; - ecm->srvid = srvid; - memcpy(ecm->ecmd5, ecmd5, CS_ECMSTORESIZE); - ecm->csp_hash = csp_hash; - ecm->rc = E_FOUND; - memcpy(ecm->cw, cw, sizeof(ecm->cw)); - ecm->grp = rdr->grp; - ecm->selected_reader = rdr; -#ifdef CS_CACHEEX_AIO - ecm->ecm_time = ecm_time; - ecm->localgenerated = er->localgenerated; -#endif -#ifdef CS_CACHEEX - if(rdr && cacheex_reader(rdr)) - { ecm->cacheex_src = rdr->client; } //so adds hits to reader -#endif - - add_cache(ecm); //add cw to cache - -#ifdef CS_CACHEEX - cs_writelock(__func__, &ecm_pushed_deleted_lock); - ecm->next = ecm_pushed_deleted; - ecm_pushed_deleted = ecm; - cs_writeunlock(__func__, &ecm_pushed_deleted_lock); -#else - NULLFREE(ecm); -#endif - } -} - -void chk_dcw(struct s_ecm_answer *ea) -{ - if(!ea || !ea->er) - { return; } - - ECM_REQUEST *ert = ea->er; - struct s_ecm_answer *ea_list; - struct s_reader *eardr = ea->reader; - if(!ert || !eardr) - { return; } - - // ecm request already answered! - if(ert->rc < E_99) - { -#ifdef CS_CACHEEX - if(ea && ert->rc < E_NOTFOUND && ea->rc < E_NOTFOUND && memcmp(ea->cw, ert->cw, sizeof(ert->cw)) != 0) - { - char cw1[16 * 3 + 2], cw2[16 * 3 + 2]; -#ifdef WITH_DEBUG - if(cs_dblevel & D_TRACE) - { - cs_hexdump(0, ea->cw, 16, cw1, sizeof(cw1)); - cs_hexdump(0, ert->cw, 16, cw2, sizeof(cw2)); - } -#endif - char ip1[20] = "", ip2[20] = ""; - if(ea->reader && check_client(ea->reader->client)) { cs_strncpy(ip1, cs_inet_ntoa(ea->reader->client->ip), sizeof(ip1)); } - if(ert->cacheex_src) { cs_strncpy(ip2, cs_inet_ntoa(ert->cacheex_src->ip), sizeof(ip2)); } - else if(ert->selected_reader && check_client(ert->selected_reader->client)) { cs_strncpy(ip2, cs_inet_ntoa(ert->selected_reader->client->ip), sizeof(ip2)); } - - ECM_REQUEST *er = ert; - debug_ecm(D_TRACE, "WARNING2: Different CWs %s from %s(%s)<>%s(%s): %s<>%s", buf, - username(ea->reader ? ea->reader->client : ert->client), ip1, - er->cacheex_src ? username(er->cacheex_src) : (ert->selected_reader ? ert->selected_reader->label : "unknown/csp"), ip2, - cw1, cw2); - } -#endif - - return; - } - -#ifdef CS_CACHEEX - /* if answer from cacheex-1 reader, not send answer to client! - * thread check_cache will check counter and send answer to client! - * Anyway, we should check if we have to go to oher stage (>1) - */ - - if(eardr && cacheex_reader(eardr)) - { - // if wait_time, and not wait_time expired and wait_time due to hitcache(or awtime>0), - // we have to wait cacheex timeout before call other readers (stage>1) - if(cacheex_reader(eardr) && !ert->cacheex_wait_time_expired && ert->cacheex_hitcache) - { return; } - - int8_t cacheex_left = 0; - uint8_t has_cacheex = 0; - if(ert->stage == 1) - { - for(ea_list = ert->matching_rdr; ea_list; ea_list = ea_list->next) - { - cs_readlock(__func__, &ea_list->ecmanswer_lock); - if(((ea_list->status & (READER_CACHEEX | READER_FALLBACK | READER_ACTIVE))) == (READER_CACHEEX | READER_ACTIVE)) - { has_cacheex = 1; } - if((!(ea_list->status & READER_FALLBACK) && ((ea_list->status & (REQUEST_SENT | REQUEST_ANSWERED | READER_CACHEEX | READER_ACTIVE)) == (REQUEST_SENT | READER_CACHEEX | READER_ACTIVE))) || ea_list->rc < E_NOTFOUND) - { cacheex_left++; } - cs_readunlock(__func__, &ea_list->ecmanswer_lock); - } - - if(has_cacheex && !cacheex_left) { request_cw_from_readers(ert, 0); } - } - - return; - } -#endif - - int32_t reader_left = 0, local_left = 0, reader_not_flb_left = 0, has_not_fallback = 0, has_local = 0; - ert->selected_reader = eardr; - - switch(ea->rc) - { - case E_FOUND: - // maxparallel: register this service on the winning reader - if(eardr->maxparallel > 0) - { reader_register_service(eardr, ert->srvid, ert->client); } - - memcpy(ert->cw, ea->cw, 16); - ert->cw_ex = ea->cw_ex; - ert->rcEx = 0; - ert->rc = ea->rc; - ert->grp |= eardr->grp; - cs_strncpy(ert->msglog, ea->msglog, sizeof(ert->msglog)); -#ifdef HAVE_DVBAPI - ert->adapter_index = ea->er->adapter_index; -#endif - break; - - case E_INVALID: - case E_NOTFOUND: - { - // check if there are other readers to ask, and if not send NOT_FOUND to client - ert->rcEx = ea->rcEx; - cs_strncpy(ert->msglog, ea->msglog, sizeof(ert->msglog)); - - for(ea_list = ert->matching_rdr; ea_list; ea_list = ea_list->next) - { - cs_readlock(__func__, &ea_list->ecmanswer_lock); - - if((!(ea_list->status & READER_FALLBACK) && ((ea_list->status & (REQUEST_SENT | REQUEST_ANSWERED | READER_LOCAL | READER_ACTIVE)) == (REQUEST_SENT | READER_LOCAL | READER_ACTIVE))) || ea_list->rc < E_NOTFOUND) - { local_left++; } - - if((!(ea_list->status & READER_FALLBACK) && ((ea_list->status & (REQUEST_SENT | REQUEST_ANSWERED | READER_ACTIVE)) == (REQUEST_SENT | READER_ACTIVE))) || ea_list->rc < E_NOTFOUND) - { reader_not_flb_left++; } - - if(((ea_list->status & (REQUEST_ANSWERED | READER_ACTIVE)) == (READER_ACTIVE)) || ea_list->rc < E_NOTFOUND) - { reader_left++; } - - if(((ea_list->status & (READER_FALLBACK | READER_ACTIVE))) == (READER_ACTIVE)) - { has_not_fallback = 1; } - if(((ea_list->status & (READER_LOCAL | READER_FALLBACK | READER_ACTIVE))) == (READER_LOCAL | READER_ACTIVE)) - { has_local = 1; } - - cs_readunlock(__func__, &ea_list->ecmanswer_lock); - } - - switch(ert->stage) - { - case 2: // only local reader (used only if preferlocalcards=1) - { - if(has_local && !local_left) { request_cw_from_readers(ert, 0); } - break; - } - case 3: - { - // any fallback reader not asked yet - if(has_not_fallback && !reader_not_flb_left) { request_cw_from_readers(ert, 0); } - break; - } - } - - if(!reader_left // no more matching reader -#ifdef CS_CACHEEX - && !cfg.wait_until_ctimeout -#endif - ) - { ert->rc = E_NOTFOUND; } // so we set the return code - - break; - } - - case E_TIMEOUT: // if timeout, we have to send timeout to client: this is done by ecm_timeout callback - return; - break; - - case E_UNHANDLED: - return; - break; - - default: - cs_log("unexpected ecm answer rc=%d.", ea->rc); - return; - break; - } - - if(ert->rc < E_99) - send_dcw(ert->client, ert); -} - -uint32_t chk_provid(uint8_t *ecm, uint16_t caid) -{ - int32_t i, len, descriptor_length = 0; - uint32_t provid = 0; - - switch(caid >> 8) - { - case 0x01: // seca - provid = b2i(2, ecm + 3); - break; - - case 0x05: // viaccess - i = (ecm[4] == 0xD2) ? ecm[5] + 2 : 0; // skip d2 nano - if((ecm[5 + i] == 3) && ((ecm[4 + i] == 0x90) || (ecm[4 + i] == 0x40))) - { provid = (b2i(3, ecm + 6 + i) & 0xFFFFF0); } - - i = (ecm[6] == 0xD2) ? ecm[7] + 2 : 0; // skip d2 nano long ecm - if((ecm[7 + i] == 7) && ((ecm[6 + i] == 0x90) || (ecm[6 + i] == 0x40))) - { provid = (b2i(3, ecm + 8 + i) & 0xFFFFF0); } - break; - - case 0x0D: // cryptoworks - len = (((ecm[1] & 0xf) << 8) | ecm[2]) + 3; - for(i = 8; i < len; i += descriptor_length + 2) - { - descriptor_length = ecm[i + 1]; - if(ecm[i] == 0x83) - { - provid = (uint32_t)ecm[i + 2] & 0xFE; - break; - } - } - break; - - case 0x18: // nagra2 - if (caid == 0x1801) // more safety - provid = b2i(2, ecm + 5); - break; - } - - return provid; -} - -void update_chid(ECM_REQUEST *er) -{ - er->chid = get_subid(er); -} - -/* - * This function writes the current CW from ECM struct to a cwl file. - * The filename is re-calculated and file re-opened every time. - * This will consume a bit cpu time, but nothing has to be stored between - * each call. If not file exists, a header is prepended - */ -static void logCWtoFile(ECM_REQUEST *er, uint8_t *cw) -{ - FILE *pfCWL; - char srvname[CS_SERVICENAME_SIZE]; - /* %s / %s _I %04X _ %s .cwl */ - char buf[256 + sizeof(srvname)]; - char date[9]; - uint8_t i, parity, writeheader = 0; - struct tm timeinfo; - - /* - * search service name for that id and change characters - * causing problems in file name - */ - - get_servicename(cur_client(), er->srvid, er->prid, er->caid, srvname, sizeof(srvname)); - - for(i = 0; srvname[i]; i++) - if(srvname[i] == ' ') { srvname[i] = '_'; } - - /* calc log file name */ - time_t walltime = cs_time(); - localtime_r(&walltime, &timeinfo); - strftime(date, sizeof(date), "%Y%m%d", &timeinfo); - snprintf(buf, sizeof(buf), "%s/%s_I%04X_%s.cwl", cfg.cwlogdir, date, er->srvid, srvname); - - /* open failed, assuming file does not exist, yet */ - if((pfCWL = fopen(buf, "r")) == NULL) - { - writeheader = 1; - } - else - { - /* we need to close the file if it was opened correctly */ - fclose(pfCWL); - } - - if((pfCWL = fopen(buf, "a+")) == NULL) - { - /* maybe this fails because the subdir does not exist. Is there a common function to create it? - for the moment do not print32_t to log on every ecm - cs_log(""error opening cw logfile for writing: %s (errno=%d %s)", buf, errno, strerror(errno)); */ - return; - } - if(writeheader) - { - /* no global macro for cardserver name :( */ - fprintf(pfCWL, "# OSCam cardserver v%s - %s\n", CS_VERSION, SCM_URL); - fprintf(pfCWL, "# control word log file for use with tsdec offline decrypter\n"); - strftime(buf, sizeof(buf), "DATE %Y-%m-%d, TIME %H:%M:%S, TZ %Z\n", &timeinfo); - fprintf(pfCWL, "# %s", buf); - fprintf(pfCWL, "# CAID 0x%04X, SID 0x%04X, SERVICE \"%s\"\n", er->caid, er->srvid, srvname); - } - - parity = er->ecm[0] & 1; - fprintf(pfCWL, "%d ", parity); - for(i = parity * 8; i < 8 + parity * 8; i++) - { fprintf(pfCWL, "%02X ", cw[i]); } - /* better use incoming time er->tps rather than current time? */ - strftime(buf, sizeof(buf), "%H:%M:%S\n", &timeinfo); - fprintf(pfCWL, "# %s", buf); - fflush(pfCWL); - fclose(pfCWL); -} - -int32_t write_ecm_answer(struct s_reader *reader, ECM_REQUEST *er, int8_t rc, uint8_t rcEx, uint8_t *cw, char *msglog, uint16_t used_cardtier, EXTENDED_CW* cw_ex) -{ - if(!reader || !er || !er->tps.time) { return 0; } - - // drop too late answers, to avoid seg fault --> only answer until tps.time+((cfg.ctimeout+500)/1000+1) is accepted - time_t timeout = time(NULL) - ((cfg.ctimeout + 500) / 1000 + 1); - if(er->tps.time < timeout) // < and NOT <= - { return 0; } - - struct timeb now; - cs_ftime(&now); - -#ifdef CS_CACHEEX_AIO - uint8_t dontsetAnswered = 0; -#endif - uint8_t dontwriteStats = 0; - - if(er && er->parent) - { - // parent is only set on reader->client->ecmtask[], but we want original er - ECM_REQUEST *er_reader_cp = er; - er = er->parent; // Now er is "original" ecm, before it was the reader-copy - er_reader_cp->rc = rc; - er_reader_cp->idx = 0; -#ifdef CS_CACHEEX_AIO - er->localgenerated = er_reader_cp->localgenerated; -#endif - - timeout = time(NULL) - ((cfg.ctimeout + 500) / 1000 + 1); - if(er->tps.time < timeout) - { return 0; } - } - -#ifdef CS_CACHEEX_AIO - if(rc < E_NOTFOUND && !er->localgenerated && (reader->cacheex.localgenerated_only_in || chk_lg_only(er, &reader->cacheex.lg_only_in_tab)) && !chk_srvid_localgenerated_only_exception(er)) - { - cs_log_dbg(D_CACHEEX, "reader: %s !er->localgenerated - rc: E_NOTFOUND set, no stats written for reader", reader ? reader->label : "-"); - rc = E_NOTFOUND; - dontsetAnswered = 1; - dontwriteStats = 1; - } -#endif - - struct s_ecm_answer *ea = get_ecm_answer(reader, er); - if(!ea) { return 0; } - - cs_writelock(__func__, &ea->ecmanswer_lock); - - if((ea->status & REQUEST_ANSWERED)) - { - cs_log_dbg(D_READER, "Reader %s already answer, skip this ecm answer!", reader ? reader->label : "-"); - cs_writeunlock(__func__, &ea->ecmanswer_lock); - return 0; - } - - // Special checks for rc - // Skip check for BISS1 - cw could be zero but still catch cw=0 by anticascading - // Skip check for BISS2 - we use the extended cw, so the "simple" cw is always zero - - // bad/wrong chksum/ecm - if(rc == E_NOTFOUND && rcEx == E2_WRONG_CHKSUM) - { - cs_log_dbg(D_READER, "ECM for reader %s was bad/has a wrong chksum!", reader ? reader->label : "-"); - rc = E_INVALID; - rcEx = E2_WRONG_CHKSUM; - er->stage = 5; - - // dont write stats for bad/wrong chksum/ecm - dontwriteStats = 1; - - // set all other matching_readers => inactive to skip them and dont spread the bad ecm - struct s_ecm_answer *ea_list; - for(ea_list = er->matching_rdr; ea_list; ea_list = ea_list->next) - { - ea_list->status &= ~(READER_ACTIVE | READER_FALLBACK); - } - } - - if(rc < E_NOTFOUND && cw && chk_is_null_CW(cw) && !caid_is_biss(er->caid)) - { - rc = E_NOTFOUND; - cs_log_dbg(D_TRACE | D_LB, "WARNING: reader %s send fake cw, set rc=E_NOTFOUND!", reader ? reader->label : "-"); - } - - if(rc < E_NOTFOUND && cw && !chk_halfCW(er,cw)) - { - rc = E_NOTFOUND; - cs_log_dbg(D_TRACE | D_LB, "WARNING: reader %s send wrong swapped NDS cw, set rc=E_NOTFOUND!", reader ? reader->label : "-"); - } - - if(reader && cw && rc < E_NOTFOUND) - { - if(!cfg.disablecrccws && !reader->disablecrccws) - { - if(!chk_if_ignore_checksum(er, &cfg.disablecrccws_only_for) && !chk_if_ignore_checksum(er, &reader->disablecrccws_only_for)) - { - uint8_t i, c; - for(i = 0; i < 16; i += 4) - { - c = ((cw[i] + cw[i + 1] + cw[i + 2]) & 0xff); - - if(cw[i + 3] != c) - { - uint8_t nano = 0x00; - if(er->caid == 0x100 && er->ecm[5] > 0x00) - { - nano = er->ecm[5]; // seca nano protection - } - - if(reader->dropbadcws && !nano) // only drop controlword if no cw encryption is applied - { - rc = E_NOTFOUND; - rcEx = E2_WRONG_CHKSUM; - break; - } - else - { - if(!nano) // only fix checksum if no cw encryption is applied (nano = 0) - { - cs_log_dbg(D_TRACE, "notice: changed dcw checksum byte cw[%i] from %02x to %02x", i + 3, cw[i + 3], c); - cw[i + 3] = c; - } - else - { - if(i == 12) // there are servers delivering correct controlwords but with failing last cw checksum (on purpose?!) - { - cs_log_dbg(D_TRACE,"NANO%02d: BAD PEER DETECTED, oscam has fixed the last cw crc that wasn't matching!", nano); - cw[i + 3] = c; // fix the last controlword - } - else - { - cs_log_dbg(D_TRACE,"NANO%02d: not fixing the crc of this cw since its still encrypted!", nano); - break; // crc failed so stop! - } - } - } - } - } - } - else - { - cs_log_dbg(D_TRACE, "notice: CW checksum check disabled for %04X:%06X", er->caid, er->prid); - } - } - else - { - cs_log_dbg(D_TRACE, "notice: CW checksum check disabled"); - } - - if(chk_if_ignore_checksum(er, &reader->disablecrccws_only_for) && caid_is_videoguard(er->caid) -#ifdef CS_CACHEEX_AIO - && !chk_srvid_disablecrccws_only_for_exception(er) -#endif - ) - { - uint8_t k, csum; - uint8_t hit = 0; - uint8_t oe = checkCWpart(cw, 0) ? 0 : 8; - for(k = 0; k < 8; k += 4) - { - csum = ((cw[k + oe] + cw[k + oe + 1] + cw[k + oe + 2]) & 0xff); - if(cw[k + oe + 3] == csum) - { - hit++; - } - } - if(hit > 1) - { - char ecmd5s[17 * 3]; - cs_hexdump(0, er->ecmd5, 16, ecmd5s, sizeof(ecmd5s)); - if(reader->dropbadcws) - { - rc = E_NOTFOUND; - rcEx = E2_WRONG_CHKSUM; - cs_log("Probably got bad CW from reader: %s, caid %04X, srvid %04X (%s) - dropping CW, lg: %i", reader->label, er->caid, er->srvid, ecmd5s -#ifdef CS_CACHEEX_AIO - , er->localgenerated); -#else - , 0); -#endif - } - else - { - cs_log("Probably got bad CW from reader: %s, caid %04X, srvid %04X (%s), lg: %i", reader->label, er->caid, er->srvid, ecmd5s -#ifdef CS_CACHEEX_AIO - , er->localgenerated); -#else - , 0); -#endif - } - } - } - - } - -#ifdef CW_CYCLE_CHECK - uint8_t cwc_ct = er->cwc_cycletime > 0 ? er->cwc_cycletime : 0; - uint8_t cwc_ncwc = er->cwc_next_cw_cycle < 2 ? er->cwc_next_cw_cycle : 2; - if(!checkcwcycle(er->client, er, reader, cw, rc, cwc_ct, cwc_ncwc)) - { -#ifdef CS_CACHEEX_AIO - if(!er->localgenerated) - { -#endif - rc = E_NOTFOUND; - rcEx = E2_WRONG_CHKSUM; - cs_log_dbg(D_CACHEEX | D_CWC | D_LB, "{client %s, caid %04X, srvid %04X} [write_ecm_answer] cyclecheck failed! Reader: %s set rc: %i", (er->client ? er->client->account->usr : "-"), er->caid, er->srvid, reader ? reader->label : "-", rc); - -#ifdef CS_CACHEEX_AIO - } - else - { - cs_log_dbg(D_CACHEEX | D_CWC | D_LB, "{client %s, caid %04X, srvid %04X} [write_ecm_answer] cyclecheck failed! Reader: %s set rc: %i -> lg-flagged CW -> do nothing", (er->client ? er->client->account->usr : "-"), er->caid, er->srvid, reader ? reader->label : "-", rc); - } -#endif - } - else { cs_log_dbg(D_CACHEEX | D_CWC | D_LB, "{client %s, caid %04X, srvid %04X} [write_ecm_answer] cyclecheck passed! Reader: %s rc: %i", (er->client ? er->client->account->usr : "-"), er->caid, er->srvid, reader ? reader->label : "-", rc); } -#endif - //END -- SPECIAL CHECKs for rc - -#ifdef CS_CACHEEX_AIO - if(!dontsetAnswered) - { -#endif - ea->status |= REQUEST_ANSWERED; -#ifdef CS_CACHEEX_AIO - } -#endif - ea->rc = rc; - ea->ecm_time = comp_timeb(&now, &ea->time_request_sent); - if(ea->ecm_time < 1) { ea->ecm_time = 1; } // set ecm_time 1 if answer immediately - ea->rcEx = rcEx; - if(cw) { memcpy(ea->cw, cw, 16); } - if(msglog) { memcpy(ea->msglog, msglog, MSGLOGSIZE); } - ea->tier = used_cardtier; - if(cw_ex) - { - ea->cw_ex = *cw_ex; - } - - cs_writeunlock(__func__, &ea->ecmanswer_lock); - - struct timeb tpe; - cs_ftime(&tpe); - int32_t ntime = comp_timeb(&tpe, &er->tps); - if(ntime < 1) { ntime = 1; } - cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} [write_ecm_answer] reader %s rc %d, ecm time %d ms (%d ms)", (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid, reader ? reader->label : "-", rc, ea->ecm_time, ntime); - - // send ea for ecm request - int32_t res = 0; - struct s_client *cl = er->client; - if(check_client(cl)) - { - res = 1; - add_job(er->client, ACTION_ECM_ANSWER_READER, ea, 0); // chk_dcw - } - - // distribute ea for pendings - if(ea->pending) // has pending ea - { distribute_ea(ea); } - - - if(!ea->is_pending) // not for pending ea - only once for ea - { - // cache update - // Skip check for BISS1 - cw could be indeed zero - // Skip check for BISS2 - we use the extended cw, so the "simple" cw is always zero - if(ea && (ea->rc < E_NOTFOUND) && (!chk_is_null_CW(ea->cw) && !caid_is_biss(er->caid))) - { -#ifdef CS_CACHEEX_AIO - int32_t ecmtime = ea->ecm_time; - - if(er->cacheex_wait_time_expired && er->cacheex_wait_time) - ecmtime = ea->ecm_time + er->cacheex_wait_time; -#endif - add_cache_from_reader(er, reader, er->csp_hash, er->ecmd5, ea->cw, er->caid, er->prid, er->srvid -#ifdef CS_CACHEEX_AIO - , ecmtime); -#else - ); -#endif - } - - if(!dontwriteStats) - { - // readers stats for LB - send_reader_stat(reader, er, ea, ea->rc); - } - - // reader checks -#ifdef WITH_DEBUG - if(cs_dblevel & D_TRACE) - { - char ecmd5[17 * 3]; - cs_hexdump(0, er->ecmd5, 16, ecmd5, sizeof(ecmd5)); - rdr_log_dbg(reader, D_TRACE, "ecm answer for ecm hash %s rc=%d", ecmd5, ea->rc); - } -#endif - // Update reader stats: - if(ea->rc == E_FOUND) - { - if(cfg.cwlogdir != NULL) - { logCWtoFile(er, ea->cw); } // CWL logging only if cwlogdir is set in config - - reader->ecmsok++; -#ifdef CS_CACHEEX_AIO - if(er->localgenerated) - reader->ecmsoklg++; -#endif - reader->webif_ecmsok++; -#ifdef CS_CACHEEX - struct s_client *eacl = reader->client; - if(cacheex_reader(reader) && check_client(eacl)) - { - eacl->cwcacheexgot++; - cacheex_add_stats(eacl, ea->er->caid, ea->er->srvid, ea->er->prid, 1 -#ifdef CS_CACHEEX_AIO - , er->localgenerated); -#else - ); -#endif - first_client->cwcacheexgot++; -#ifdef CS_CACHEEX_AIO - if(er->localgenerated) - { - eacl->cwcacheexgotlg++; - first_client->cwcacheexgotlg++; - } -#endif - } -#endif - } - else if(ea->rc == E_NOTFOUND) - { - reader->ecmsnok++; - reader->webif_ecmsnok++; - if(reader->ecmnotfoundlimit && reader->ecmsnok >= reader->ecmnotfoundlimit) - { - rdr_log(reader, "ECM not found limit reached %u. Restarting the reader.", - reader->ecmsnok); - reader->ecmsnok = 0; // Reset the variable - reader->ecmshealthnok = 0; // Reset the variable - add_job(reader->client, ACTION_READER_RESTART, NULL, 0); - } - } - - // this fixes big oscam mistake - // wrong reader status on web info aka not counted timeouts which dispalyed - // reader info 100 percent OK but reader had a ton of unhandled timeouts! - else if(ea->rc == E_TIMEOUT) - { -#ifdef WITH_LB - STAT_QUERY q; - readerinfofix_get_stat_query(er, &q); - READER_STAT *s; - s = readerinfofix_get_add_stat(reader, &q); - if (s) - { - cs_log_dbg(D_LB, "inc fail {client %s, caid %04X, prid %06X, srvid %04X} [write_ecm_answer] reader %s rc %d, ecm time %d ms (%d ms)", (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid, reader ? reader->label : "-", rc, ea->ecm_time, ntime); - readerinfofix_inc_fail(s); // now increase fail factor for unhandled timeouts - } -#endif - reader->ecmstout++; // now append timeouts to the readerinfo timeout count - reader->webif_ecmstout++; - } - - // Reader ECMs Health Try (by Pickser) - if(reader->ecmsok != 0 || reader->ecmsnok != 0 || reader->ecmstout != 0) - { - reader->ecmshealthok = ((double) reader->ecmsok / (reader->ecmsok + reader->ecmsnok + reader->ecmstout)) * 100; -#ifdef CS_CACHEEX_AIO - reader->ecmshealthoklg = ((double) reader->ecmsoklg / (reader->ecmsok + reader->ecmsnok + reader->ecmstout)) * 100; -#endif - reader->ecmshealthnok = ((double) reader->ecmsnok / (reader->ecmsok + reader->ecmsnok + reader->ecmstout)) * 100; - reader->ecmshealthtout = ((double) reader->ecmstout / (reader->ecmsok + reader->ecmsnok + reader->ecmstout)) * 100; - } - - if(rc == E_FOUND && reader->resetcycle > 0) - { - reader->resetcounter++; - if(reader->resetcounter > reader->resetcycle) - { - reader->resetcounter = 0; - rdr_log(reader, "Resetting reader, resetcyle of %d ecms reached", reader->resetcycle); - reader->card_status = CARD_NEED_INIT; - cardreader_reset(cl); - } - } - } - - return res; -} - -// chid calculation from module stat to here -// to improve the quickfix concerning ecm chid info and extend it -// to all client requests wereby the chid is known in module stat - -uint32_t get_subid(ECM_REQUEST *er) -{ - if(!er->ecmlen) - { return 0; } - - uint32_t id = 0; - switch(er->caid >> 8) - { - case 0x01: // seca - id = b2i(2, er->ecm + 7); - break; - - case 0x05: // viaccess - id = b2i(2, er->ecm + 8); - break; - - case 0x06: // irdeto - id = b2i(2, er->ecm + 6); - break; - - case 0x09: // videoguard - id = b2i(2, er->ecm + 11); - break; - - case 0x4A: // DRE-Crypt, Bulcrypt, Tongfang and others? - if(!caid_is_bulcrypt(er->caid) && !caid_is_dre(er->caid)) - { id = b2i(2, er->ecm + 6); } - break; - } - return id; -} - -static void set_readers_counter(ECM_REQUEST *er) -{ - struct s_ecm_answer *ea; - - er->reader_count = 0; - er->fallback_reader_count = 0; - er->localreader_count = 0; - er->cacheex_reader_count = 0; - - for(ea = er->matching_rdr; ea; ea = ea->next) - { - if(ea->status & READER_ACTIVE) - { - if(!(ea->status & READER_FALLBACK)) - { er->reader_count++; } - else - { er->fallback_reader_count++; } - - if(cacheex_reader(ea->reader)) - { er->cacheex_reader_count++; } - else if(is_localreader(ea->reader, er)) - { er->localreader_count++; } - } - } -} - -void write_ecm_answer_fromcache(struct s_write_from_cache *wfc) -{ - ECM_REQUEST *er = NULL; - ECM_REQUEST *ecm = NULL; - - er = wfc->er_new; - ecm = wfc->er_cache; - -#ifdef CS_CACHEEX_AIO - if(ecm->localgenerated || (ecm->cw_count > 0x0F000000)) - er->localgenerated = 1; -#endif - - int8_t rc_orig = er->rc; - - er->grp |= ecm->grp; // update group -#ifdef CS_CACHEEX - if(ecm->from_csp) { er->csp_answered = 1; } // update er as answered by csp (csp have no group) -#endif - - if(er->rc >= E_NOTFOUND) - { -#ifdef CS_CACHEEX - if(ecm->cacheex_src) // from cacheex or csp - { - er->rc = E_CACHEEX; - } - else -#endif - { er->rc=E_CACHE1; } // from normal readers - - memcpy(er->cw, ecm->cw, 16); - er->selected_reader = ecm->selected_reader; - er->cw_count = ecm->cw_count; - -#ifdef CS_CACHEEX - // here we should be sure cex client has not been freed! - if(ecm->cacheex_src && is_valid_client(ecm->cacheex_src) && !ecm->cacheex_src->kill) - { - er->cacheex_src = ecm->cacheex_src; - er->cwc_cycletime = ecm->cwc_cycletime; - er->cwc_next_cw_cycle = ecm->cwc_next_cw_cycle; - } - else - { - er->cacheex_src = NULL; - } - - int8_t cacheex = check_client(er->client) && er->client->account ? er->client->account->cacheex.mode : 0; - if(cacheex == 1 && check_client(er->client)) - { - cacheex_add_stats(er->client, er->caid, er->srvid, er->prid, 0 -#ifdef CS_CACHEEX_AIO - , er->localgenerated); -#else - ); -#endif - er->client->cwcacheexpush++; - if(er->client->account) - { er->client->account->cwcacheexpush++; } - first_client->cwcacheexpush++; - -#ifdef CS_CACHEEX_AIO - if(er->localgenerated) - { - er->client->cwcacheexpushlg++; - first_client->cwcacheexpushlg++; - } -#endif - - } -#endif - -#ifdef CS_CACHEEX - if(cfg.delay && cacheex!=1) // No delay on cacheexchange mode 1 client! - { cs_sleepms(cfg.delay); } -#else - if(cfg.delay) - { cs_sleepms(cfg.delay); } -#endif - - if(rc_orig == E_UNHANDLED) - { - cs_log_dbg(D_LB,"{client %s, caid %04X, prid %06X, srvid %04X} [write_ecm_answer_fromcache] found cw in CACHE (count %d)!", (check_client(er->client)?er->client->account->usr:"-"),er->caid, er->prid, er->srvid, -#ifdef CS_CACHEEX_AIO - (er->cw_count > 0x0F000000) ? er->cw_count ^= 0x0F000000 : er->cw_count); -#else - er->cw_count); -#endif - send_dcw(er->client, er); - } - } -} - -#ifdef CS_CACHEEX_AIO -static bool ecm_cache_check(ECM_REQUEST *er) -{ - if(ecm_cache_init_done && cfg.ecm_cache_droptime > 0) - { - ECM_CACHE *ecm_cache = NULL; - SAFE_RWLOCK_WRLOCK(&ecm_cache_lock); - ecm_cache = find_hash_table(&ht_ecm_cache, &er->csp_hash, sizeof(uint32_t), &compare_csp_hash_ecmcache); - if(!ecm_cache) - { - // ecm_cache-size(count/memory) pre-check - if( - (cfg.ecm_cache_size && (cfg.ecm_cache_size > tommy_hashlin_count(&ht_ecm_cache))) - || (cfg.ecm_cache_memory && (cfg.ecm_cache_memory*1024*1024 > tommy_hashlin_memory_usage(&ht_ecm_cache))) - ) - { - if(cs_malloc(&ecm_cache, sizeof(ECM_CACHE))) - { - ecm_cache->csp_hash = er->csp_hash; - cs_ftime(&ecm_cache->first_recv_time); - cs_ftime(&ecm_cache->upd_time); - - tommy_hashlin_insert(&ht_ecm_cache, &ecm_cache->ht_node, ecm_cache, tommy_hash_u32(0, &er->csp_hash, sizeof(er->csp_hash))); - tommy_list_insert_tail(&ll_ecm_cache, &ecm_cache->ll_node, ecm_cache); - - SAFE_RWLOCK_UNLOCK(&ecm_cache_lock); - return true; - } - else{ - SAFE_RWLOCK_UNLOCK(&ecm_cache_lock); - cs_log("[ecm_cache] ERROR: NO added HASH to ecm_cache!!"); - return false; - } - } - else{ - // clean cache call; - SAFE_RWLOCK_UNLOCK(&ecm_cache_lock); - ecm_cache_cleanup(true); - return false; - } - } - // ecm found - else{ - int64_t gone_diff = 0; - gone_diff = comp_timeb(&er->tps, &ecm_cache->first_recv_time); - cs_ftime(&ecm_cache->upd_time); - - if(gone_diff >= cfg.ecm_cache_droptime * 1000) - { - cs_log_dbg(D_CW_CACHE, "[ecm_cache] ECM drop, current ecm_cache_size: %i - ecm_cache-mem-size: %i MiB", count_hash_table(&ht_ecm_cache), (int)(tommy_hashlin_memory_usage(&ht_ecm_cache)/1024/1024)); - SAFE_RWLOCK_UNLOCK(&ecm_cache_lock); - return false; - } - } - - SAFE_RWLOCK_UNLOCK(&ecm_cache_lock); - return true; - } - else{ - cs_log_dbg(D_CW_CACHE,"[ecm_cache] ecm_cache_init_done %i cfg.ecm_cache_size: %"PRIu32" cfg.ecm_cache_memory %"PRIu32" MiB", ecm_cache_init_done, cfg.ecm_cache_size, cfg.ecm_cache_memory); - return true; - } -} -#endif - -void get_cw(struct s_client *client, ECM_REQUEST *er) -{ -#ifdef CS_CACHEEX_AIO - cacheex_update_hash(er); - if(!ecm_cache_check(er)) - { - er->rc = E_INVALID; - send_dcw(client, er); - free_ecm(er); - return; - } -#endif - cs_log_dump_dbg(D_ATR, er->ecm, er->ecmlen, "get cw for ecm:"); - cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} [get_cw] NEW REQUEST!", (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid); - increment_n_request(client); - - int32_t i, j, m; - time_t now = time((time_t *)0); - uint32_t line = 0; - uint16_t sct_len; - - er->client = client; - er->rc = E_UNHANDLED; // set default rc status to unhandled - er->cwc_next_cw_cycle = 2; // set it to: we dont know - - // user was on freetv or didn't request for some time - // so we reset lastswitch to get correct stats/webif display - if(now - client->lastecm > cfg.hideclient_to) { client->lastswitch = 0; } - client->lastecm = now; - - if(client == first_client || !client ->account || client->account == first_client->account) - { - // DVBApi+serial is allowed to request anonymous accounts: - int16_t listenertype = get_module(client)->listenertype; - if(listenertype != LIS_DVBAPI && listenertype != LIS_SERIAL) - { - er->rc = E_INVALID; - er->rcEx = E2_GLOBAL; - snprintf(er->msglog, sizeof(er->msglog), "invalid user account %s", username(client)); - } - } - - // ecmlen must be 0 (no ecm) or >2 (because SCT_LEN() needs at least 3 bytes) - if(er->ecmlen < 0 || er->ecmlen == 1 || er->ecmlen == 2) - { - er->rc = E_INVALID; - er->rcEx = E2_GLOBAL; - snprintf(er->msglog, sizeof(er->msglog), "ECM size %d invalid, ignored! client %s", er->ecmlen, username(client)); - } - - if(er->ecmlen > MAX_ECM_SIZE) - { - er->rc = E_INVALID; - er->rcEx = E2_GLOBAL; - snprintf(er->msglog, sizeof(er->msglog), "ECM size %d > Max ECM size %d, ignored! client %s", er->ecmlen, MAX_ECM_SIZE, username(client)); - } - - if(er->ecmlen > 2) - { - sct_len = SCT_LEN(er->ecm); - if(sct_len > er->ecmlen || sct_len < 4) - { - er->rc = E_INVALID; - er->rcEx = E2_GLOBAL; - snprintf(er->msglog, sizeof(er->msglog), "Real ECM size %d > ECM size %d, ignored! client %s", sct_len, er->ecmlen, username(client)); - } - er->ecmlen = sct_len; - } - - if(!client->grp) - { - er->rc = E_INVALID; - er->rcEx = E2_GROUP; - snprintf(er->msglog, sizeof(er->msglog), "invalid user group %s", username(client)); - } - - // add chid for all client requests as in module stat - update_chid(er); - - // betacrypt ecm with nagra header - if(chk_is_betatunnel_caid(er->caid) == 1 && (er->ecmlen == 0x89 || er->ecmlen == 0x4A) && er->ecm[3] == 0x07 && (er->ecm[4] == 0x84 || er->ecm[4] == 0x45)) - { - if(er->caid == 0x1702) - { - er->caid = 0x1833; - } - else - { - check_lb_auto_betatunnel_mode(er); - } - cs_log_dbg(D_TRACE, "Quickfix remap beta->nagra: 0x%X, 0x%X, 0x%X, 0x%X", er->caid, er->ecmlen, er->ecm[3], er->ecm[4]); - } - - // nagra ecm with betacrypt header 1801, 1833, 1834, 1835 - if(chk_is_betatunnel_caid(er->caid) == 2 && (er->ecmlen == 0x93 || er->ecmlen == 0x54) && er->ecm[13] == 0x07 && (er->ecm[14] == 0x84 || er->ecm[14] == 0x45)) - { - if(er->caid == 0x1833) - { - er->caid = 0x1702; - } - else - { - er->caid = 0x1722; - } - cs_log_dbg(D_TRACE, "Quickfix remap nagra->beta: 0x%X, 0x%X, 0x%X, 0x%X", er->caid, er->ecmlen, er->ecm[13], er->ecm[44]); - } - - // Ariva quickfix (invalid nagra provider) - if(((er->caid & 0xFF00) == 0x1800) && er->prid > 0x00FFFF) - { er->prid = 0; } - - // Check for invalid provider, extract provider out of ecm: - uint32_t prid = chk_provid(er->ecm, er->caid); - if(!er->prid) - { - er->prid = prid; - } - else - { - if(prid && prid != er->prid) - { - cs_log_dbg(D_TRACE, "provider fixed: %04X@%06X to %04X@%06X", er->caid, er->prid, er->caid, prid); - er->prid = prid; - } - } - -#ifdef MODULE_NEWCAMD - // Set providerid for newcamd clients if none is given - if(!er->prid && client->ncd_server) - { - int32_t pi = client->port_idx; - if(pi >= 0 && cfg.ncd_ptab.nports && cfg.ncd_ptab.nports >= pi && cfg.ncd_ptab.ports[pi].ncd) - { er->prid = cfg.ncd_ptab.ports[pi].ncd->ncd_ftab.filts[0].prids[0]; } - } -#endif - - // CAID not supported or found - if(!er->caid) - { - er->rc = E_INVALID; - er->rcEx = E2_CAID; - snprintf(er->msglog, MSGLOGSIZE, "CAID not supported or found"); - } - - // user expired - if(client->expirationdate && client->expirationdate < client->lastecm) - { er->rc = E_EXPDATE; } - - // out of timeframe - if(client->allowedtimeframe_set) - { - struct tm acttm; - localtime_r(&now, &acttm); - int32_t curday = acttm.tm_wday; - char *dest = strstr(weekdstr,"ALL"); - int32_t all_idx = (dest - weekdstr) / 3; - uint8_t allowed = 0; - - // checkout if current time is allowed in the current day - allowed = CHECK_BIT(client->allowedtimeframe[curday][acttm.tm_hour][acttm.tm_min / 30], (acttm.tm_min % 30)); - - // or checkout if current time is allowed for all days - allowed |= CHECK_BIT(client->allowedtimeframe[all_idx][acttm.tm_hour][acttm.tm_min / 30], (acttm.tm_min % 30)); - - if(!(allowed)) - { - er->rc = E_EXPDATE; - } - cs_log_dbg(D_TRACE, "Check Timeframe - result: %d, day:%s time: %02dH%02d, allowed: %s\n", er->rc, shortDay[curday], acttm.tm_hour, acttm.tm_min, allowed ? "true" : "false"); - } - - // user disabled - if(client->disabled != 0) - { - if(client->failban & BAN_DISABLED) - { - cs_add_violation(client, client->account->usr); - cs_disconnect_client(client); - } - er->rc = E_DISABLED; - } - - if(!chk_global_whitelist(er, &line)) - { - debug_ecm(D_TRACE, "whitelist filtered: %s (%s) line %d", username(client), buf, line); - er->rc = E_INVALID; - } - -#ifdef CS_CACHEEX - if(client->account && client->account->cacheex.mode == 2 && !client->account->cacheex.allow_request) - { - er->rc = E_INVALID; - snprintf(er->msglog, MSGLOGSIZE, "invalid request from cacheex-2 client"); - } -#endif - - // rc < 100 -> ecm error - if(er->rc >= E_UNHANDLED) - { - m = er->caid; - i = er->srvid; - - if(i != client->last_srvid || !client->lastswitch) - { - if(cfg.usrfileflag) - { cs_statistics(client); } - client->lastswitch = now; - } - - // user sleeping - if(client->tosleep && (now - client->lastswitch > client->tosleep)) - { - if(client->failban & BAN_SLEEPING) - { - cs_add_violation(client, client->account->usr); - cs_disconnect_client(client); - } - if(client->c35_sleepsend != 0) - { - er->rc = E_STOPPED; // send sleep command CMD08 {00 255} - } - else - { - er->rc = E_SLEEPING; - } - } - - client->last_srvid = i; - client->last_caid = m; - client->last_provid = er->prid; - - int32_t ecm_len = (((er->ecm[1] & 0x0F) << 8) | er->ecm[2]) + 3; - - for(j = 0; (j < 6) && (er->rc >= E_UNHANDLED); j++) - { - switch(j) - { - case 0: - // fake (uniq) - if(client->dup) - { er->rc = E_FAKE; } - break; - - case 1: - // invalid (caid) - if(!chk_bcaid(er, &client->ctab)) - { - er->rc = E_INVALID; - er->rcEx = E2_CAID; - snprintf(er->msglog, MSGLOGSIZE, "invalid caid 0x%04X", er->caid); - } - break; - - case 2: - // invalid (srvid) - // matching srvids (or 0000) specified in betatunnel will bypass this filter - if(!chk_srvid(client, er)) - { - if(!chk_on_btun(SRVID_ZERO, client, er)) - { - er->rc = E_INVALID; - snprintf(er->msglog, MSGLOGSIZE, "invalid SID"); - } - } - break; - - case 3: - // invalid (ufilters) - if(!chk_ufilters(er)) - { er->rc = E_INVALID; } - break; - - case 4: - // invalid (sfilter) - if(!chk_sfilter(er, &get_module(client)->ptab)) - { er->rc = E_INVALID; } - break; - - case 5: - // corrupt - if((i = er->ecmlen - ecm_len)) - { - if(i > 0) - { - cs_log_dbg(D_TRACE, "warning: ecm size adjusted from %d to %d", er->ecmlen, ecm_len); - er->ecmlen = ecm_len; - } - else - { er->rc = E_CORRUPT; } - } - break; - } - } - } - - // Check for odd/even byte - // Don't check for BISS1 and BISS2 mode 1/E or fake caid (ECM is fake for them) - // Don't check for BISS2 mode CA (ECM table is always 0x80) - if(!caid_is_biss(er->caid) && !caid_is_fake(er->caid) && get_odd_even(er) == 0) - { - cs_log_dbg(D_TRACE, "warning: ecm with null odd/even byte from %s", (check_client(er->client) ? er->client->account->usr : "-")); - er->rc = E_INVALID; - } - - // not continue, send rc to client - if(er->rc < E_UNHANDLED) - { - send_dcw(client, er); - free_ecm(er); - return; - } - - -#ifdef CS_CACHEEX - int8_t cacheex = client->account ? client->account->cacheex.mode : 0; - er->from_cacheex1_client = 0; - if(cacheex == 1) {er->from_cacheex1_client = 1;} -#endif - - - // set preferlocalcards for this ecm request (actually, paramter - // is per user based, maybe in fiture it will be caid based too) - er->preferlocalcards = cfg.preferlocalcards; - if(client->account && client->account->preferlocalcards > -1) - { - er->preferlocalcards = client->account->preferlocalcards; - } - if(er->preferlocalcards <0 || er->preferlocalcards >2) {er->preferlocalcards=0;} - - - if(chk_is_betatunnel_caid(er->caid) && client->ttab.ttnum) - { - cs_log_dump_dbg(D_TRACE, er->ecm, 13, "betatunnel? ecmlen=%d", er->ecmlen); - cs_betatunnel(er); - } - - - // ignore ecm... - int32_t offset = 3; - - // ...and betacrypt header for cache md5 calculation - if(caid_is_betacrypt(er->caid)) - { offset = 13; } - - uint8_t md5tmp[MD5_DIGEST_LENGTH]; - - // store ECM in cache - memcpy(er->ecmd5, MD5(er->ecm + offset, er->ecmlen - offset, md5tmp), CS_ECMSTORESIZE); - cacheex_update_hash(er); - ac_chk(client, er, 0); - - - //******** CHECK IF FOUND ECM IN CACHE - struct ecm_request_t *ecm = NULL; - ecm = check_cache(er, client); - if(ecm) // found in cache - { - cs_log_dbg(D_LB,"{client %s, caid %04X, prid %06X, srvid %04X} [get_cw] cw found immediately in cache! ", (check_client(er->client)?er->client->account->usr:"-"),er->caid, er->prid, er->srvid); - - struct s_write_from_cache *wfc = NULL; - if(!cs_malloc(&wfc, sizeof(struct s_write_from_cache))) - { - NULLFREE(ecm); - free_ecm(er); - return; - } - - wfc->er_new = er; - wfc->er_cache = ecm; - write_ecm_answer_fromcache(wfc); - NULLFREE(wfc); - NULLFREE(ecm); - free_ecm(er); - - return; - } - -// zaplist ACoSC -#ifdef CS_ANTICASC - if(cfg.acosc_enabled) - { - cs_writelock(__func__, &clientlist_lock); - insert_zaplist(er, client); - cs_writeunlock(__func__, &clientlist_lock); - } -#endif - - er->reader_avail = 0; - er->readers = 0; - - struct s_ecm_answer *ea, *prv = NULL; - struct s_reader *rdr; - - cs_readlock(__func__, &readerlist_lock); - cs_readlock(__func__, &clientlist_lock); - - for(rdr = first_active_reader; rdr; rdr = rdr->next) - { - uint8_t is_fallback = chk_is_fixed_fallback(rdr, er); - int8_t match = matching_reader(er, rdr); - - if(!match) // if this reader does not match, check betatunnel for it - match = lb_check_auto_betatunnel(er, rdr); - - if(match) - { - er->reader_avail++; - -#ifdef CS_CACHEEX - if(cacheex == 1 && !cacheex_reader(rdr)) // ex1-cl only ask ex1-rdr - { continue; } -#endif - - if(!cs_malloc(&ea, sizeof(struct s_ecm_answer))) - { goto OUT; } - -#ifdef WITH_EXTENDED_CW - // Correct CSA mode is CBC - default to that instead - ea->cw_ex.algo_mode = CW_ALGO_MODE_CBC; -#endif - - er->readers++; - - ea->reader = rdr; - ea->er = er; - ea->rc = E_UNHANDLED; - if(prv) - { prv->next = ea; } - else - { er->matching_rdr = ea; } - prv = ea; - - ea->status = READER_ACTIVE; - if(cacheex_reader(rdr)) - { ea->status |= READER_CACHEEX; } - else if(is_localreader(rdr, er)) - { ea->status |= READER_LOCAL; } - - if(is_fallback && (!is_localreader(rdr, er) || (is_localreader(rdr, er) && !er->preferlocalcards))) - { ea->status |= READER_FALLBACK; } - - ea->pending = NULL; - ea->is_pending = false; - cs_lock_create(__func__, &ea->ecmanswer_lock, "ecmanswer_lock", 5000); - } - } - -OUT: - cs_readunlock(__func__, &clientlist_lock); - cs_readunlock(__func__, &readerlist_lock); - - lb_set_best_reader(er); - - // set reader_count and fallback_reader_count - set_readers_counter(er); - - // if preferlocalcards > 0, check if we have local readers selected: - // if not, switch to preferlocalcards = 0 for this ecm - if(er->preferlocalcards > 0) - { - if(er->localreader_count == 0) - { - er->preferlocalcards = 0; - cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} NO local readers, set preferlocalcards = %d", - (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid, er->preferlocalcards); - } - } - -#ifdef CS_CACHEEX - // WAIT_TIME - uint32_t cacheex_wait_time = 0; - uint32_t wait_time_no_hitcache = 0; - uint32_t wait_time_hitcache = 0; - - if(client->account && !client->account->no_wait_time -#ifdef CS_CACHEEX_AIO - && !chk_srvid_no_wait_time(er) -#endif - && er->preferlocalcards<2) - { - wait_time_no_hitcache = get_cacheex_wait_time(er,NULL); // NO check hitcache. Wait_time is dwtime, or, if 0, awtime. - wait_time_hitcache = get_cacheex_wait_time(er,client); // check hitcache for calculating wait_time! If hitcache wait_time is biggest value between dwtime and awtime, else it's awtime. - - if( - // If "normal" client and ex1-rdr>0, we cannot use hitcache for calculating wait_time because we cannot know if cw is available or not on ex1 server! - (cacheex != 1 && er->cacheex_reader_count) - || - /* Cw for ex1-cl comes from: INT. cache by "normal" readers (normal clients that ask normal readers), ex1-rdr and ex2-rdr and ex3-rdr. - * If readers, we have to wait cws generating by normal clients asking normal readers and answers by ex1-rdr (cannot use hitcache). - * If no readers, use hitcache for calculating wait_time. - */ - (cacheex == 1 && er->reader_avail) - ) - { cacheex_wait_time = wait_time_no_hitcache; } - else - { cacheex_wait_time = wait_time_hitcache; } - } - - cs_log_dbg(D_TRACE | D_CACHEEX, "[GET_CW] wait_time %d caid %04X prov %06X srvid %04X rc %d cacheex cl mode %d ex1rdr %d", cacheex_wait_time, er->caid, er->prid, er->srvid, er->rc, cacheex, er->cacheex_reader_count); - cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} [get_cw] wait_time %d - client cacheex mode %d, reader avail for ecm %d, hitcache %d, preferlocalcards %d", (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid, cacheex_wait_time, cacheex == 1 ? 1 : 0, er->reader_avail, wait_time_hitcache ? 1 : 0, er->preferlocalcards); - // END WAIT_TIME calculation - - if(!cacheex_wait_time && (er->reader_count + er->fallback_reader_count) == 0) -#else - if((er->reader_count + er->fallback_reader_count) == 0) -#endif - { - er->rc = E_NOTFOUND; - if(!er->rcEx) - { er->rcEx = E2_GROUP; } - snprintf(er->msglog, MSGLOGSIZE, "no matching reader"); - cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} [get_cw] NO Readers and NO wait_time... not_found! ", (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid); - send_dcw(client, er); - free_ecm(er); - return; - } - - //insert it in ecmcwcache! - cs_writelock(__func__, &ecmcache_lock); - er->next = ecmcwcache; - ecmcwcache = er; - ecmcwcache_size++; - cs_writeunlock(__func__, &ecmcache_lock); - - er->rcEx = 0; -#ifdef CS_CACHEEX - er->cacheex_wait_time = 0; - er->cacheex_wait_time_expired = 1; - er->cacheex_hitcache = 0; - er->cacheex_mode1_delay = 0; - - if(cacheex_wait_time) // wait time for cacheex - { - er->cacheex_wait_time = cacheex_wait_time; - er->cacheex_wait_time_expired = 0; - er->cacheex_hitcache = wait_time_hitcache ? 1 : 0; // usefull only when cacheex mode 1 readers answers before wait_time and we have to decide if we have to wait until wait_time expires. - er->cacheex_mode1_delay = get_cacheex_mode1_delay(er); - - if(!er->cacheex_mode1_delay && er->cacheex_reader_count > 0) - { - request_cw_from_readers(er, 1); // setting stop_stage=1, we request only cacheex mode 1 readers. Others are requested at cacheex timeout! - } - } - else -#endif - request_cw_from_readers(er, 0); - -#ifdef WITH_DEBUG - if(D_CLIENTECM & cs_dblevel) - { - char buf[ECM_FMT_LEN]; - format_ecm(er, buf, ECM_FMT_LEN); - cs_log_dump_dbg(D_CLIENTECM, er->ecm, er->ecmlen, "Client %s ECM dump %s", username(client), buf); - } -#endif - - cw_process_thread_wakeup(); -} - -int32_t ecmfmt(char *result, size_t size, uint16_t caid, uint16_t onid, uint32_t prid, uint16_t chid, uint16_t pid, - uint16_t srvid, uint16_t l, char *ecmd5hex, char *csphash, char *cw, uint16_t origin_peer, uint8_t distance, char *payload, char *tier) -{ - if(!cfg.ecmfmt) - { - if(tier && payload) - { - return snprintf(result, size, "%04X@%06X/%04X/%04X/%02X:%s:0F06%s:%s", caid, prid, chid, srvid, l, ecmd5hex, payload, tier); - } - else if(tier) - { - return snprintf(result, size, "%04X@%06X/%04X/%04X/%02X:%s:%s", caid, prid, chid, srvid, l, ecmd5hex, tier); - } - else if(payload) - { - return snprintf(result, size, "%04X@%06X/%04X/%04X/%02X:%s:0F06%s", caid, prid, chid, srvid, l, ecmd5hex, payload); - } - else - { - return snprintf(result, size, "%04X@%06X/%04X/%04X/%02X:%s", caid, prid, chid, srvid, l, ecmd5hex); - } - } - -#define ECMFMT_NUMBER 0 -#define ECMFMT_STRING 1 -#define ECMFMT_CHAR 2 - - uint8_t type = 0; - uint32_t ivalue = 0; - char *ifmt = NULL, *sfmt = NULL; - char *svalue = NULL, cvalue = '\0'; - uint8_t hide_if_zero = 0; - char *c; - uint32_t s = 0; - - for(c = cfg.ecmfmt; *c; c++) - { - if(*c == '0') - { - hide_if_zero = 1; - continue; - } - - sfmt = NULL; - - switch(*c) - { - case 't': - type = ECMFMT_STRING; - svalue = tier; - if(tier == NULL && !hide_if_zero) - { - type = ECMFMT_NUMBER; - ifmt = "%04X"; - ivalue = 0; - } - break; - - case 'c': - type = ECMFMT_NUMBER; - ifmt = "%04X"; - ivalue = caid; - break; - - case 'o': - type = ECMFMT_NUMBER; - ifmt = "%04X"; - ivalue = onid; - break; - - case 'p': - type = ECMFMT_NUMBER; - ifmt = "%06X"; - ivalue = prid; - break; - - case 'i': - type = ECMFMT_NUMBER; - ifmt = "%04X"; - ivalue = chid; - break; - - case 'd': - type = ECMFMT_NUMBER; - ifmt = "%04X"; - ivalue = pid; - break; - - case 's': - type = ECMFMT_NUMBER; - ifmt = "%04X"; - ivalue = srvid; - break; - - case 'l': - type = ECMFMT_NUMBER; - ifmt = "%02X"; - ivalue = l; - break; - - case 'h': - type = ECMFMT_STRING; - svalue = ecmd5hex; - break; - - case 'e': - type = ECMFMT_STRING; - svalue = csphash; - break; - - case 'w': - type = ECMFMT_STRING; - svalue = cw; - break; - - case 'j': - type = ECMFMT_NUMBER; - ifmt = "%02X"; - ivalue = distance; - break; - - case 'g': - type = ECMFMT_NUMBER; - ifmt = "%04X"; - ivalue = origin_peer; - break; - - case '\\': - c++; - type = ECMFMT_CHAR; - cvalue = *c; - - if(cvalue == '\0') - { return s; } - break; - - case 'y': - type = ECMFMT_STRING; - svalue = payload; - sfmt = "0F06%.06s"; - if(payload == NULL && !hide_if_zero) - { - type = ECMFMT_NUMBER; - ifmt = "0F06%06X"; - ivalue = 0; - } - break; - - case 'Y': - type = ECMFMT_STRING; - svalue = payload; - sfmt = "0F06%s"; - if(payload == NULL && !hide_if_zero) - { - type = ECMFMT_NUMBER; - ifmt = "0F06%12X"; - ivalue = 0; - } - break; - - default: - type = ECMFMT_CHAR; - cvalue = *c; - break; - } - - if(hide_if_zero) - { - if(type == ECMFMT_NUMBER && ivalue == 0) - { - hide_if_zero = 0; - continue; - } - else if(type == ECMFMT_STRING && svalue == NULL) - { - hide_if_zero = 0; - continue; - } - } - - switch(type) - { - case ECMFMT_NUMBER: - s += snprintf(result + s, size - s, ifmt, ivalue); - break; - - case ECMFMT_STRING: - s += snprintf(result + s, size - s , sfmt != NULL ? sfmt : "%s", svalue); - break; - - case ECMFMT_CHAR: - if(size - s > 1) - { - result[s] = cvalue; - result[s+1] = '\0'; - s++; - } - break; - - default: - break; - } - } - - return s; -} - -int32_t format_ecm(ECM_REQUEST *ecm, char *result, size_t size) -{ - char ecmd5hex[(16*2)+1]; - char csphash[(4*2)+1] = { 0 }; - char cwhex[(16*2)+1]; - char *payload = NULL; - char *tier = NULL; -#ifdef READER_VIDEOGUARD - char payload_string[(6*2)+1]; - char tier_string[83]; - struct s_ecm_answer *ea; - - if(ecm->selected_reader && caid_is_videoguard(ecm->selected_reader->caid) && !is_network_reader(ecm->selected_reader)) - { - for(ea = ecm->matching_rdr; ea; ea = ea->next) - { - if(ea->tier && (ea->status & REQUEST_ANSWERED) && !is_network_reader(ea->reader)) - { - get_tiername_defaultid(ea->tier, ecm->selected_reader->caid, tier_string); - tier = tier_string; - break; - } - } - - cs_hexdump(0, ecm->selected_reader->VgLastPayload, 6, payload_string, sizeof(payload_string)); - payload = payload_string; - } -#endif - cs_hexdump(0, ecm->ecmd5, 16, ecmd5hex, sizeof(ecmd5hex)); -#ifdef CS_CACHEEX - cs_hexdump(0, (void *)&ecm->csp_hash, 4, csphash, sizeof(csphash)); -#endif - cs_hexdump(0, ecm->cw, 16, cwhex, sizeof(cwhex)); -#ifdef MODULE_GBOX - if(check_client(ecm->client) && get_module(ecm->client)->num == R_GBOX && ecm->gbox_ecm_dist) - { return ecmfmt(result, size, ecm->caid, ecm->onid, ecm->prid, ecm->chid, ecm->pid, ecm->srvid, ecm->ecmlen, ecmd5hex, csphash, cwhex, ecm->gbox_ecm_src_peer, ecm->gbox_ecm_dist, payload, tier); } - else if (ecm->selected_reader && ecm->selected_reader->typ == R_GBOX && !ecm->gbox_ecm_dist) - { return ecmfmt(result, size, ecm->caid, ecm->onid, ecm->prid, ecm->chid, ecm->pid, ecm->srvid, ecm->ecmlen, ecmd5hex, csphash, cwhex, ecm->selected_reader->gbox_cw_src_peer, ecm->selected_reader->currenthops, payload, tier); } - else -#endif - return ecmfmt(result, size, ecm->caid, ecm->onid, ecm->prid, ecm->chid, ecm->pid, ecm->srvid, ecm->ecmlen, ecmd5hex, csphash, cwhex, 0, - ((ecm->selected_reader && ecm->selected_reader->currenthops) ? ecm->selected_reader->currenthops : 0), payload, tier); -} diff --git a/oscam-ecm.h b/oscam-ecm.h old mode 100644 new mode 100755 diff --git a/oscam-emm-cache.c b/oscam-emm-cache.c old mode 100644 new mode 100755 diff --git a/oscam-emm-cache.h b/oscam-emm-cache.h old mode 100644 new mode 100755 diff --git a/oscam-emm.c b/oscam-emm.c old mode 100644 new mode 100755 diff --git a/oscam-emm.h b/oscam-emm.h old mode 100644 new mode 100755 diff --git a/oscam-failban.c b/oscam-failban.c old mode 100644 new mode 100755 diff --git a/oscam-failban.h b/oscam-failban.h old mode 100644 new mode 100755 diff --git a/oscam-files.c b/oscam-files.c old mode 100644 new mode 100755 diff --git a/oscam-files.h b/oscam-files.h old mode 100644 new mode 100755 diff --git a/oscam-garbage.c b/oscam-garbage.c old mode 100644 new mode 100755 diff --git a/oscam-garbage.h b/oscam-garbage.h old mode 100644 new mode 100755 diff --git a/oscam-hashtable.c b/oscam-hashtable.c old mode 100644 new mode 100755 diff --git a/oscam-hashtable.h b/oscam-hashtable.h old mode 100644 new mode 100755 diff --git a/oscam-llist.c b/oscam-llist.c old mode 100644 new mode 100755 diff --git a/oscam-llist.h b/oscam-llist.h old mode 100644 new mode 100755 diff --git a/oscam-lock.c b/oscam-lock.c old mode 100644 new mode 100755 diff --git a/oscam-lock.h b/oscam-lock.h old mode 100644 new mode 100755 diff --git a/oscam-log-reader.c b/oscam-log-reader.c old mode 100644 new mode 100755 diff --git a/oscam-log-reader.h b/oscam-log-reader.h old mode 100644 new mode 100755 diff --git a/oscam-log.c b/oscam-log.c old mode 100644 new mode 100755 diff --git a/oscam-log.h b/oscam-log.h old mode 100644 new mode 100755 diff --git a/oscam-net.c b/oscam-net.c old mode 100644 new mode 100755 diff --git a/oscam-net.h b/oscam-net.h old mode 100644 new mode 100755 diff --git a/oscam-reader.c b/oscam-reader.c old mode 100644 new mode 100755 diff --git a/oscam-reader.h b/oscam-reader.h old mode 100644 new mode 100755 diff --git a/oscam-signing.c b/oscam-signing.c old mode 100644 new mode 100755 diff --git a/oscam-signing.h b/oscam-signing.h old mode 100644 new mode 100755 diff --git a/oscam-simples.c b/oscam-simples.c old mode 100644 new mode 100755 diff --git a/oscam-string-isotables.h b/oscam-string-isotables.h old mode 100644 new mode 100755 diff --git a/oscam-string.c b/oscam-string.c old mode 100644 new mode 100755 diff --git a/oscam-string.h b/oscam-string.h old mode 100644 new mode 100755 diff --git a/oscam-time.c b/oscam-time.c old mode 100644 new mode 100755 diff --git a/oscam-time.h b/oscam-time.h old mode 100644 new mode 100755 diff --git a/oscam-work.c b/oscam-work.c old mode 100644 new mode 100755 diff --git a/oscam-work.h b/oscam-work.h old mode 100644 new mode 100755 diff --git a/oscam.c b/oscam.c old mode 100644 new mode 100755 diff --git a/rcEx b/rcEx old mode 100644 new mode 100755 diff --git a/reader-bulcrypt.c b/reader-bulcrypt.c old mode 100644 new mode 100755 diff --git a/reader-common.c b/reader-common.c old mode 100644 new mode 100755 diff --git a/reader-common.h b/reader-common.h old mode 100644 new mode 100755 diff --git a/reader-conax.c b/reader-conax.c old mode 100644 new mode 100755 diff --git a/reader-cryptoworks.c b/reader-cryptoworks.c old mode 100644 new mode 100755 diff --git a/reader-dgcrypt.c b/reader-dgcrypt.c old mode 100644 new mode 100755 diff --git a/reader-dre-cas.c b/reader-dre-cas.c old mode 100644 new mode 100755 diff --git a/reader-dre-common.c b/reader-dre-common.c old mode 100644 new mode 100755 diff --git a/reader-dre-common.h b/reader-dre-common.h old mode 100644 new mode 100755 diff --git a/reader-dre-st20.c b/reader-dre-st20.c old mode 100644 new mode 100755 diff --git a/reader-dre-st20.h b/reader-dre-st20.h old mode 100644 new mode 100755 diff --git a/reader-dre.c b/reader-dre.c old mode 100644 new mode 100755 diff --git a/reader-griffin.c b/reader-griffin.c old mode 100644 new mode 100755 diff --git a/reader-irdeto.c b/reader-irdeto.c old mode 100644 new mode 100755 diff --git a/reader-irdeto.h b/reader-irdeto.h old mode 100644 new mode 100755 diff --git a/reader-nagra-common.c b/reader-nagra-common.c old mode 100644 new mode 100755 diff --git a/reader-nagra-common.h b/reader-nagra-common.h old mode 100644 new mode 100755 diff --git a/reader-nagra.c b/reader-nagra.c old mode 100644 new mode 100755 diff --git a/reader-nagracak7.c b/reader-nagracak7.c old mode 100644 new mode 100755 diff --git a/reader-seca.c b/reader-seca.c old mode 100644 new mode 100755 diff --git a/reader-tongfang.c b/reader-tongfang.c old mode 100644 new mode 100755 diff --git a/reader-viaccess.c b/reader-viaccess.c old mode 100644 new mode 100755 diff --git a/reader-videoguard-common.c b/reader-videoguard-common.c old mode 100644 new mode 100755 diff --git a/reader-videoguard-common.h b/reader-videoguard-common.h old mode 100644 new mode 100755 diff --git a/reader-videoguard1.c b/reader-videoguard1.c old mode 100644 new mode 100755 diff --git a/reader-videoguard12.c b/reader-videoguard12.c old mode 100644 new mode 100755 diff --git a/reader-videoguard2.c b/reader-videoguard2.c old mode 100644 new mode 100755 diff --git a/readers.h b/readers.h old mode 100644 new mode 100755 diff --git a/tests.c b/tests.c old mode 100644 new mode 100755 diff --git a/tier b/tier old mode 100644 new mode 100755 diff --git a/tommyDS_hashlin/tommychain.h b/tommyDS_hashlin/tommychain.h old mode 100644 new mode 100755 diff --git a/tommyDS_hashlin/tommyhash.c b/tommyDS_hashlin/tommyhash.c old mode 100644 new mode 100755 diff --git a/tommyDS_hashlin/tommyhash.h b/tommyDS_hashlin/tommyhash.h old mode 100644 new mode 100755 diff --git a/tommyDS_hashlin/tommyhashlin.c b/tommyDS_hashlin/tommyhashlin.c old mode 100644 new mode 100755 diff --git a/tommyDS_hashlin/tommyhashlin.h b/tommyDS_hashlin/tommyhashlin.h old mode 100644 new mode 100755 diff --git a/tommyDS_hashlin/tommylist.c b/tommyDS_hashlin/tommylist.c old mode 100644 new mode 100755 diff --git a/tommyDS_hashlin/tommylist.h b/tommyDS_hashlin/tommylist.h old mode 100644 new mode 100755 diff --git a/tommyDS_hashlin/tommytypes.h b/tommyDS_hashlin/tommytypes.h old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-arm-coolstream.cmake b/toolchains/toolchain-arm-coolstream.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-arm-dockstar-openwrt.cmake b/toolchains/toolchain-arm-dockstar-openwrt.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-arm-friendlyarm.cmake b/toolchains/toolchain-arm-friendlyarm.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-arm-mca.cmake b/toolchains/toolchain-arm-mca.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-arm-none.cmake b/toolchains/toolchain-arm-none.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-arm-nslu2-openwrt.cmake b/toolchains/toolchain-arm-nslu2-openwrt.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-arm-nslu2-unslung.cmake b/toolchains/toolchain-arm-nslu2-unslung.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-arm-su980.cmake b/toolchains/toolchain-arm-su980.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-arm-wrt350nv2-openwrt.cmake b/toolchains/toolchain-arm-wrt350nv2-openwrt.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-mips-agv2_w.cmake b/toolchains/toolchain-mips-agv2_w.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-mips-azbox.cmake b/toolchains/toolchain-mips-azbox.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-mips-dir825.cmake b/toolchains/toolchain-mips-dir825.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-mips-fonera2.cmake b/toolchains/toolchain-mips-fonera2.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-mips-tuxbox.cmake b/toolchains/toolchain-mips-tuxbox.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-mips-wrt54g.cmake b/toolchains/toolchain-mips-wrt54g.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-mipsel-tuxbox-broken-pthread.cmake b/toolchains/toolchain-mipsel-tuxbox-broken-pthread.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-mipsel-tuxbox-linux-gnu.cmake b/toolchains/toolchain-mipsel-tuxbox-linux-gnu.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-mipsel-tuxbox.cmake b/toolchains/toolchain-mipsel-tuxbox.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-powerpc-tuxbox.cmake b/toolchains/toolchain-powerpc-tuxbox.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-sh4-amino.cmake b/toolchains/toolchain-sh4-amino.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-sh4-qboxhd.cmake b/toolchains/toolchain-sh4-qboxhd.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-sh4-tuxbox-stapi.cmake b/toolchains/toolchain-sh4-tuxbox-stapi.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-sh4-tuxbox.cmake b/toolchains/toolchain-sh4-tuxbox.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-sparc-padre.cmake b/toolchains/toolchain-sparc-padre.cmake old mode 100644 new mode 100755 diff --git a/toolchains/toolchain-tripledragon.cmake b/toolchains/toolchain-tripledragon.cmake old mode 100644 new mode 100755 diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt old mode 100644 new mode 100755 diff --git a/utils/list_smargo.c b/utils/list_smargo.c old mode 100644 new mode 100755 diff --git a/webif/.gitignore b/webif/.gitignore old mode 100644 new mode 100755 diff --git a/webif/Makefile b/webif/Makefile old mode 100644 new mode 100755 diff --git a/webif/README b/webif/README old mode 100644 new mode 100755 diff --git a/webif/api.json/cacheex.json b/webif/api.json/cacheex.json old mode 100644 new mode 100755 diff --git a/webif/api.json/cacheexaiobit.json b/webif/api.json/cacheexaiobit.json old mode 100644 new mode 100755 diff --git a/webif/api.json/cacheexbit.json b/webif/api.json/cacheexbit.json old mode 100644 new mode 100755 diff --git a/webif/api.json/entitlementbit.json b/webif/api.json/entitlementbit.json old mode 100644 new mode 100755 diff --git a/webif/api.json/entitlements.json b/webif/api.json/entitlements.json old mode 100644 new mode 100755 diff --git a/webif/api.json/footer.json b/webif/api.json/footer.json old mode 100644 new mode 100755 diff --git a/webif/api.json/header.json b/webif/api.json/header.json old mode 100644 new mode 100755 diff --git a/webif/api.json/reader.json b/webif/api.json/reader.json old mode 100644 new mode 100755 diff --git a/webif/api.json/readerbit.json b/webif/api.json/readerbit.json old mode 100644 new mode 100755 diff --git a/webif/api.json/status.json b/webif/api.json/status.json old mode 100644 new mode 100755 diff --git a/webif/api.json/status_statusbits.json b/webif/api.json/status_statusbits.json old mode 100644 new mode 100755 diff --git a/webif/api.json/user.json b/webif/api.json/user.json old mode 100644 new mode 100755 diff --git a/webif/api.json/userbit.json b/webif/api.json/userbit.json old mode 100644 new mode 100755 diff --git a/webif/api.xml/cccamcardlist.xml b/webif/api.xml/cccamcardlist.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/cccamcardlist_cardlist.xml b/webif/api.xml/cccamcardlist_cardlist.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/cccamcardlist_cardlist_nodelist.xml b/webif/api.xml/cccamcardlist_cardlist_nodelist.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/cccamcardlist_cardlist_providerlist.xml b/webif/api.xml/cccamcardlist_cardlist_providerlist.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/confirmation.xml b/webif/api.xml/confirmation.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/error.xml b/webif/api.xml/error.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/failban.xml b/webif/api.xml/failban.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/failban_failbanrow.xml b/webif/api.xml/failban_failbanrow.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/file.xml b/webif/api.xml/file.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/footer.xml b/webif/api.xml/footer.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/header.xml b/webif/api.xml/header.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/readers.xml b/webif/api.xml/readers.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/readers_readerlist.xml b/webif/api.xml/readers_readerlist.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/readerstats.xml b/webif/api.xml/readerstats.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/readerstats_ecmstats.xml b/webif/api.xml/readerstats_ecmstats.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/readerstats_emmstats.xml b/webif/api.xml/readerstats_emmstats.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/status.xml b/webif/api.xml/status.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/status_statusbits.xml b/webif/api.xml/status_statusbits.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/userconfiglist.xml b/webif/api.xml/userconfiglist.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/userconfiglist_userconfigs.xml b/webif/api.xml/userconfiglist_userconfigs.xml old mode 100644 new mode 100755 diff --git a/webif/api.xml/useredit.xml b/webif/api.xml/useredit.xml old mode 100644 new mode 100755 diff --git a/webif/cacheex/cacheex.html b/webif/cacheex/cacheex.html old mode 100644 new mode 100755 diff --git a/webif/cacheex/cacheex_tablerow.html b/webif/cacheex/cacheex_tablerow.html old mode 100644 new mode 100755 diff --git a/webif/cacheexaio/cacheex.html b/webif/cacheexaio/cacheex.html old mode 100644 new mode 100755 diff --git a/webif/cacheexaio/cacheex_tablerow.html b/webif/cacheexaio/cacheex_tablerow.html old mode 100644 new mode 100755 diff --git a/webif/cacheexaio/cacheex_tablerow_stats.html b/webif/cacheexaio/cacheex_tablerow_stats.html old mode 100644 new mode 100755 diff --git a/webif/config/anticasc.html b/webif/config/anticasc.html old mode 100644 new mode 100755 diff --git a/webif/config/cache.html b/webif/config/cache.html old mode 100644 new mode 100755 diff --git a/webif/config/cache_cacheexaiocsp.html b/webif/config/cache_cacheexaiocsp.html old mode 100644 new mode 100755 diff --git a/webif/config/cache_cacheexaiocsp.html.bak b/webif/config/cache_cacheexaiocsp.html.bak old mode 100644 new mode 100755 diff --git a/webif/config/cache_cacheexcsp.html b/webif/config/cache_cacheexcsp.html old mode 100644 new mode 100755 diff --git a/webif/config/cache_cwcycle.html b/webif/config/cache_cwcycle.html old mode 100644 new mode 100755 diff --git a/webif/config/cacheaio.html b/webif/config/cacheaio.html old mode 100644 new mode 100755 diff --git a/webif/config/camd33.html b/webif/config/camd33.html old mode 100644 new mode 100755 diff --git a/webif/config/camd35.html b/webif/config/camd35.html old mode 100644 new mode 100755 diff --git a/webif/config/camd35tcp.html b/webif/config/camd35tcp.html old mode 100644 new mode 100755 diff --git a/webif/config/cccam.html b/webif/config/cccam.html old mode 100644 new mode 100755 diff --git a/webif/config/cccam_control.html b/webif/config/cccam_control.html old mode 100644 new mode 100755 diff --git a/webif/config/cccreshare.html b/webif/config/cccreshare.html old mode 100644 new mode 100755 diff --git a/webif/config/config.html b/webif/config/config.html old mode 100644 new mode 100755 diff --git a/webif/config/dvbapi.html b/webif/config/dvbapi.html old mode 100644 new mode 100755 diff --git a/webif/config/dvbapi_demuxerfix.html b/webif/config/dvbapi_demuxerfix.html old mode 100644 new mode 100755 diff --git a/webif/config/dvbapi_extended_cw_api.html b/webif/config/dvbapi_extended_cw_api.html old mode 100644 new mode 100755 diff --git a/webif/config/gbox.html b/webif/config/gbox.html old mode 100644 new mode 100755 diff --git a/webif/config/global.html b/webif/config/global.html old mode 100644 new mode 100755 diff --git a/webif/config/global.html.bak b/webif/config/global.html.bak old mode 100644 new mode 100755 diff --git a/webif/config/global_cacheex_aio_logging.html b/webif/config/global_cacheex_aio_logging.html old mode 100644 new mode 100755 diff --git a/webif/config/global_enableledbit.html b/webif/config/global_enableledbit.html old mode 100644 new mode 100755 diff --git a/webif/config/global_getblockemmauprovid.html b/webif/config/global_getblockemmauprovid.html old mode 100644 new mode 100755 diff --git a/webif/config/global_localcards.html b/webif/config/global_localcards.html old mode 100644 new mode 100755 diff --git a/webif/config/global_suppresscmd08.html b/webif/config/global_suppresscmd08.html old mode 100644 new mode 100755 diff --git a/webif/config/global_unlockparental.html b/webif/config/global_unlockparental.html old mode 100644 new mode 100755 diff --git a/webif/config/lcd.html b/webif/config/lcd.html old mode 100644 new mode 100755 diff --git a/webif/config/loadbalancer.html b/webif/config/loadbalancer.html old mode 100644 new mode 100755 diff --git a/webif/config/loadbalancer_control.html b/webif/config/loadbalancer_control.html old mode 100644 new mode 100755 diff --git a/webif/config/menu.html b/webif/config/menu.html old mode 100644 new mode 100755 diff --git a/webif/config/menu_anticasc.html b/webif/config/menu_anticasc.html old mode 100644 new mode 100755 diff --git a/webif/config/menu_camd33.html b/webif/config/menu_camd33.html old mode 100644 new mode 100755 diff --git a/webif/config/menu_camd35.html b/webif/config/menu_camd35.html old mode 100644 new mode 100755 diff --git a/webif/config/menu_camd35tcp.html b/webif/config/menu_camd35tcp.html old mode 100644 new mode 100755 diff --git a/webif/config/menu_cccam.html b/webif/config/menu_cccam.html old mode 100644 new mode 100755 diff --git a/webif/config/menu_cmcaptioncwc.html b/webif/config/menu_cmcaptioncwc.html old mode 100644 new mode 100755 diff --git a/webif/config/menu_dvbapi.html b/webif/config/menu_dvbapi.html old mode 100644 new mode 100755 diff --git a/webif/config/menu_gbox.html b/webif/config/menu_gbox.html old mode 100644 new mode 100755 diff --git a/webif/config/menu_lcd.html b/webif/config/menu_lcd.html old mode 100644 new mode 100755 diff --git a/webif/config/menu_loadbalancer.html b/webif/config/menu_loadbalancer.html old mode 100644 new mode 100755 diff --git a/webif/config/menu_monitor.html b/webif/config/menu_monitor.html old mode 100644 new mode 100755 diff --git a/webif/config/menu_newcamd.html b/webif/config/menu_newcamd.html old mode 100644 new mode 100755 diff --git a/webif/config/menu_radegast.html b/webif/config/menu_radegast.html old mode 100644 new mode 100755 diff --git a/webif/config/menu_scam.html b/webif/config/menu_scam.html old mode 100644 new mode 100755 diff --git a/webif/config/menu_serial.html b/webif/config/menu_serial.html old mode 100644 new mode 100755 diff --git a/webif/config/menu_streamrelay.html b/webif/config/menu_streamrelay.html old mode 100644 new mode 100755 diff --git a/webif/config/monitor.html b/webif/config/monitor.html old mode 100644 new mode 100755 diff --git a/webif/config/newcamd.html b/webif/config/newcamd.html old mode 100644 new mode 100755 diff --git a/webif/config/radegast.html b/webif/config/radegast.html old mode 100644 new mode 100755 diff --git a/webif/config/scam.html b/webif/config/scam.html old mode 100644 new mode 100755 diff --git a/webif/config/serial.html b/webif/config/serial.html old mode 100644 new mode 100755 diff --git a/webif/config/serial_devices.html b/webif/config/serial_devices.html old mode 100644 new mode 100755 diff --git a/webif/config/streamrelay.html b/webif/config/streamrelay.html old mode 100644 new mode 100755 diff --git a/webif/config/streamrelay_emusettings.html b/webif/config/streamrelay_emusettings.html deleted file mode 100755 index dcb0618..0000000 --- a/webif/config/streamrelay_emusettings.html +++ /dev/null @@ -1,9 +0,0 @@ - Process EMM from stream (emu): - - - - - ECM fix delay (emu): diff --git a/webif/config/webif.html b/webif/config/webif.html old mode 100644 new mode 100755 diff --git a/webif/config/webif_httpssl.html b/webif/config/webif_httpssl.html old mode 100644 new mode 100755 diff --git a/webif/config/webif_show_jquery.html b/webif/config/webif_show_jquery.html old mode 100644 new mode 100755 diff --git a/webif/config/webif_showcacheexinfo.html b/webif/config/webif_showcacheexinfo.html old mode 100644 new mode 100755 diff --git a/webif/emm/emm.html b/webif/emm/emm.html old mode 100644 new mode 100755 diff --git a/webif/emm_running/emm_running.html b/webif/emm_running/emm_running.html old mode 100644 new mode 100755 diff --git a/webif/entitlements/entitlements.html b/webif/entitlements/entitlements.html old mode 100644 new mode 100755 diff --git a/webif/entitlements/entitlements_bit.html b/webif/entitlements/entitlements_bit.html old mode 100644 new mode 100755 diff --git a/webif/entitlements/entitlements_bit_nds.html b/webif/entitlements/entitlements_bit_nds.html old mode 100644 new mode 100755 diff --git a/webif/entitlements/entitlements_cccambit.html b/webif/entitlements/entitlements_cccambit.html old mode 100644 new mode 100755 diff --git a/webif/entitlements/entitlements_cccambit_statsentry.html b/webif/entitlements/entitlements_cccambit_statsentry.html old mode 100644 new mode 100755 diff --git a/webif/entitlements/entitlements_genericbit.html b/webif/entitlements/entitlements_genericbit.html old mode 100644 new mode 100755 diff --git a/webif/entitlements/entitlements_itembit.html b/webif/entitlements/entitlements_itembit.html old mode 100644 new mode 100755 diff --git a/webif/failban/failban.html b/webif/failban/failban.html old mode 100644 new mode 100755 diff --git a/webif/failban/failban_failbanrow.html b/webif/failban/failban_failbanrow.html old mode 100644 new mode 100755 diff --git a/webif/files/file.html b/webif/files/file.html old mode 100644 new mode 100755 diff --git a/webif/files/file_edit_css.html b/webif/files/file_edit_css.html old mode 100644 new mode 100755 diff --git a/webif/files/file_filterform.html b/webif/files/file_filterform.html old mode 100644 new mode 100755 diff --git a/webif/files/file_writeprotection.html b/webif/files/file_writeprotection.html old mode 100644 new mode 100755 diff --git a/webif/files/menu.html b/webif/files/menu.html old mode 100644 new mode 100755 diff --git a/webif/files/menu_anticasc.html b/webif/files/menu_anticasc.html old mode 100644 new mode 100755 diff --git a/webif/files/menu_constantcw.html b/webif/files/menu_constantcw.html old mode 100644 new mode 100755 diff --git a/webif/files/menu_dvbapi.html b/webif/files/menu_dvbapi.html old mode 100644 new mode 100755 diff --git a/webif/files/menu_fakecws.html b/webif/files/menu_fakecws.html old mode 100644 new mode 100755 diff --git a/webif/files/menu_gbox.html b/webif/files/menu_gbox.html old mode 100644 new mode 100755 diff --git a/webif/files/menu_softcamkey.html b/webif/files/menu_softcamkey.html deleted file mode 100755 index cf71877..0000000 --- a/webif/files/menu_softcamkey.html +++ /dev/null @@ -1 +0,0 @@ -
  • SoftCam.Key
  • diff --git a/webif/files/menu_twin.html b/webif/files/menu_twin.html old mode 100644 new mode 100755 diff --git a/webif/ghttp/autoconf.html b/webif/ghttp/autoconf.html old mode 100644 new mode 100755 diff --git a/webif/ghttp/pre_autoconf.html b/webif/ghttp/pre_autoconf.html old mode 100644 new mode 100755 diff --git a/webif/graph/graph.svg b/webif/graph/graph.svg old mode 100644 new mode 100755 diff --git a/webif/images/ICARRL.svg b/webif/images/ICARRL.svg old mode 100644 new mode 100755 diff --git a/webif/images/ICARRR.svg b/webif/images/ICARRR.svg old mode 100644 new mode 100755 diff --git a/webif/images/ICDEL.svg b/webif/images/ICDEL.svg old mode 100644 new mode 100755 diff --git a/webif/images/ICDIS.svg b/webif/images/ICDIS.svg old mode 100644 new mode 100755 diff --git a/webif/images/ICEDI.svg b/webif/images/ICEDI.svg old mode 100644 new mode 100755 diff --git a/webif/images/ICEMM.svg b/webif/images/ICEMM.svg old mode 100644 new mode 100755 diff --git a/webif/images/ICENA.svg b/webif/images/ICENA.svg old mode 100644 new mode 100755 diff --git a/webif/images/ICENT.svg b/webif/images/ICENT.svg old mode 100644 new mode 100755 diff --git a/webif/images/ICHID.svg b/webif/images/ICHID.svg old mode 100644 new mode 100755 diff --git a/webif/images/ICKIL.svg b/webif/images/ICKIL.svg old mode 100644 new mode 100755 diff --git a/webif/images/ICMLOGO.svg b/webif/images/ICMLOGO.svg old mode 100644 new mode 100755 diff --git a/webif/images/ICREF.svg b/webif/images/ICREF.svg old mode 100644 new mode 100755 diff --git a/webif/images/ICRES.svg b/webif/images/ICRES.svg old mode 100644 new mode 100755 diff --git a/webif/images/ICSHW.svg b/webif/images/ICSHW.svg old mode 100644 new mode 100755 diff --git a/webif/images/ICSPAC.gif b/webif/images/ICSPAC.gif old mode 100644 new mode 100755 diff --git a/webif/images/ICSTA.svg b/webif/images/ICSTA.svg old mode 100644 new mode 100755 diff --git a/webif/images/ICSTART.svg b/webif/images/ICSTART.svg old mode 100644 new mode 100755 diff --git a/webif/images/ICSTOP.svg b/webif/images/ICSTOP.svg old mode 100644 new mode 100755 diff --git a/webif/images/favicon.ico b/webif/images/favicon.ico old mode 100644 new mode 100755 diff --git a/webif/include/body.html b/webif/include/body.html old mode 100644 new mode 100755 diff --git a/webif/include/cccamentitlements.html b/webif/include/cccamentitlements.html old mode 100644 new mode 100755 diff --git a/webif/include/cccamentitletooltip.html b/webif/include/cccamentitletooltip.html old mode 100644 new mode 100755 diff --git a/webif/include/css.css b/webif/include/css.css old mode 100644 new mode 100755 diff --git a/webif/include/footer.html b/webif/include/footer.html old mode 100644 new mode 100755 diff --git a/webif/include/foundentitlements.html b/webif/include/foundentitlements.html old mode 100644 new mode 100755 diff --git a/webif/include/header.html b/webif/include/header.html old mode 100644 new mode 100755 diff --git a/webif/include/header_short.html b/webif/include/header_short.html old mode 100644 new mode 100755 diff --git a/webif/include/jquery.js b/webif/include/jquery.js old mode 100644 new mode 100755 diff --git a/webif/include/jscript.js b/webif/include/jscript.js old mode 100644 new mode 100755 diff --git a/webif/include/logobit.html b/webif/include/logobit.html old mode 100644 new mode 100755 diff --git a/webif/include/logobit_img.html b/webif/include/logobit_img.html old mode 100644 new mode 100755 diff --git a/webif/include/menu.html b/webif/include/menu.html old mode 100644 new mode 100755 diff --git a/webif/include/menu_cacheexmenuitem.html b/webif/include/menu_cacheexmenuitem.html old mode 100644 new mode 100755 diff --git a/webif/include/message.html b/webif/include/message.html old mode 100644 new mode 100755 diff --git a/webif/include/message_bit.html b/webif/include/message_bit.html old mode 100644 new mode 100755 diff --git a/webif/include/noentitlements.html b/webif/include/noentitlements.html old mode 100644 new mode 100755 diff --git a/webif/include/poll.html b/webif/include/poll.html old mode 100644 new mode 100755 diff --git a/webif/include/pollingset.html b/webif/include/pollingset.html old mode 100644 new mode 100755 diff --git a/webif/include/protocamd3aiopic.html b/webif/include/protocamd3aiopic.html old mode 100644 new mode 100755 diff --git a/webif/include/protocccampic.html b/webif/include/protocccampic.html old mode 100644 new mode 100755 diff --git a/webif/include/protonewcamdpic.html b/webif/include/protonewcamdpic.html old mode 100644 new mode 100755 diff --git a/webif/include/protootherpic.html b/webif/include/protootherpic.html old mode 100644 new mode 100755 diff --git a/webif/include/refresh.html b/webif/include/refresh.html old mode 100644 new mode 100755 diff --git a/webif/logmenu/log_clearlog.html b/webif/logmenu/log_clearlog.html old mode 100644 new mode 100755 diff --git a/webif/logmenu/log_clearuserlog.html b/webif/logmenu/log_clearuserlog.html old mode 100644 new mode 100755 diff --git a/webif/logmenu/log_disablelogmenu.html b/webif/logmenu/log_disablelogmenu.html old mode 100644 new mode 100755 diff --git a/webif/logmenu/log_filterform.html b/webif/logmenu/log_filterform.html old mode 100644 new mode 100755 diff --git a/webif/logmenu/log_logmenuonoff.html b/webif/logmenu/log_logmenuonoff.html old mode 100644 new mode 100755 diff --git a/webif/logpage/logpage.html b/webif/logpage/logpage.html old mode 100644 new mode 100755 diff --git a/webif/logpage/logpage_debugmenu.html b/webif/logpage/logpage_debugmenu.html old mode 100644 new mode 100755 diff --git a/webif/logpage/logpage_menu.html b/webif/logpage/logpage_menu.html old mode 100644 new mode 100755 diff --git a/webif/logpage/logpage_sizemenu.html b/webif/logpage/logpage_sizemenu.html old mode 100644 new mode 100755 diff --git a/webif/pages_gen.c b/webif/pages_gen.c old mode 100644 new mode 100755 diff --git a/webif/pages_index.txt b/webif/pages_index.txt old mode 100644 new mode 100755 diff --git a/webif/pages_index_check b/webif/pages_index_check old mode 100644 new mode 100755 diff --git a/webif/pages_mkdep b/webif/pages_mkdep old mode 100644 new mode 100755 diff --git a/webif/pages_wiki.c b/webif/pages_wiki.c deleted file mode 100644 index 760461e..0000000 --- a/webif/pages_wiki.c +++ /dev/null @@ -1,754 +0,0 @@ -/* - * OSCam WebIf Wiki data - AUTO GENERATED, DO NOT EDIT! - * Generated by wiki_gen from wiki markdown files - */ -#define MODULE_LOG_PREFIX "webif" -#include "../globals.h" - -#if defined(WEBIF) && defined(WEBIF_WIKI) - -#include "pages_wiki.h" -#include - -static const struct wiki_entry wiki_entries[] = { - { .param = "Parameters", .config = "ratelimit", .section = "", .text = "- **CAID**: Conditional Access Identification in hexadecimal (e.g., 0100, 0500, 1702)\n- **provider ID**: Provider ID in hexadecimal (e.g., 000000, 003411)\n- **service ID**: Service ID in hexadecimal (specific channel or use wildcard)\n- **ChID**: Channel ID in hexadecimal\n- **ratelimitecm**: Number of different SIDs (channels) allowed within the time interval\n- **ratelimitseconds**: Time interval in seconds for the rate limit\n- **srvidholdseconds**: Extra time in seconds a service ID is kept in a slot before another service ID can take its place", .status = 0 }, - { .param = "Rate", .config = "ratelimit", .section = "", .text = "1. OSCam tracks ECM requests for each CAID:ProvID combination\n2. It maintains a list of recently accessed service IDs (channels)\n3. When a new channel is requested, OSCam checks if the limit is reached\n4. If the limit is exceeded within the time window, the request is denied\n5. After the time interval expires, the counter resets", .status = 0 }, - { .param = "Slot", .config = "ratelimit", .section = "", .text = "The `srvidholdseconds` parameter adds \"stickiness\" to channel slots:\n- When you switch to a channel, it occupies a slot\n- That slot is held for the specified extra time\n- This prevents rapid slot turnover and encourages staying on channels longer\n- After the hold time expires, the slot can be reused for a different channel", .status = 0 }, - { .param = "Preventing", .config = "ratelimit", .section = "", .text = "Limit users to 3 channels per 30 seconds:\n\n```\n1702:000000::::0003:0030:0010\n```\n\nThis allows accessing 3 different channels in 30 seconds, with each channel held for 10 extra seconds.", .status = 0 }, - { .param = "Provider-Specific", .config = "ratelimit", .section = "", .text = "Different limits for different providers:\n\n```\n# Sky Germany - 2 channels per 15 seconds\n1702:000000::::0002:0015:0005\n\n# HD+ - 4 channels per 20 seconds\n1830:003411::::0004:0020:0008\n\n# Canal+ - 3 channels per 30 seconds\n0100:003311::::0003:0030:0010\n```", .status = 0 }, - { .param = "Strict", .config = "ratelimit", .section = "", .text = "Very restrictive limit for shared cards:\n\n```\n0500:032830::::0001:0060:0030\n```\n\nThis allows only 1 channel per 60 seconds, effectively preventing channel switching for a full minute.", .status = 0 }, - { .param = "Moderate", .config = "ratelimit", .section = "", .text = "Balanced approach for normal usage:\n\n```\n# Allow 5 channels per 20 seconds\n1702:000000::::0005:0020:0005\n```", .status = 0 }, - { .param = "All", .config = "ratelimit", .section = "", .text = "```\n0100:::::0003:0030:0010\n```\n\nApplies to all providers under CAID 0100.", .status = 0 }, - { .param = "All", .config = "ratelimit", .section = "", .text = "```\n:::::0002:0015:0005\n```\n\nApplies globally to all CAIDs and providers (use with caution).", .status = 0 }, - { .param = "Setting", .config = "ratelimit", .section = "", .text = "- Consider normal viewing patterns (most users watch 1-2 channels)\n- Allow some flexibility for legitimate channel browsing\n- Balance between preventing abuse and user experience\n- Test limits with real usage before deploying", .status = 0 }, - { .param = "Time", .config = "ratelimit", .section = "", .text = "- Shorter intervals (10-20 seconds) provide tighter control\n- Longer intervals (30-60 seconds) are more lenient\n- Match intervals to your usage policy goals", .status = 0 }, - { .param = "Hold", .config = "ratelimit", .section = "", .text = "- Hold times should be shorter than the rate limit interval\n- Typical values: 3-10 seconds\n- Longer hold times discourage rapid switching\n- Too long may frustrate legitimate users", .status = 0 }, - { .param = "Monitoring", .config = "ratelimit", .section = "", .text = "- Monitor logs for rate limit violations\n- Adjust limits based on actual usage patterns\n- Consider different limits for different user groups\n- Review and update limits periodically", .status = 0 }, - { .param = "Users", .config = "ratelimit", .section = "", .text = "- Limits may be too restrictive\n- Increase `ratelimitecm` value\n- Increase `ratelimitseconds` interval\n- Reduce `srvidholdseconds` hold time", .status = 0 }, - { .param = "Abuse", .config = "ratelimit", .section = "", .text = "- Limits may be too lenient\n- Decrease `ratelimitecm` value\n- Decrease `ratelimitseconds` interval\n- Increase `srvidholdseconds` hold time", .status = 0 }, - { .param = "Legitimate", .config = "ratelimit", .section = "", .text = "- Review actual usage patterns\n- Adjust limits to accommodate normal behavior\n- Consider different limits for trusted users\n- Use per-user limits in oscam.user instead", .status = 0 }, - { .param = "Parameters", .config = "ac", .section = "", .text = "- **CAID**: Conditional Access Identification - numeric identifier for the encryption provider\n- **provider ID**: Numeric identifier for the Pay TV provider\n- **seconds**: Time interval in seconds defining the minimum time between control word changes\n\nThe asterisk (*) can be used to define a default value for all providers not explicitly listed.", .status = 0 }, - { .param = "Basic", .config = "ac", .section = "", .text = "```\n0100:000000=10\n*=7\n```\n\nFor CAID 0100 with provider 000000, the time interval is set to 10 seconds. For all other CAIDs not explicitly defined, the default interval is 7 seconds.", .status = 0 }, - { .param = "Sky", .config = "ac", .section = "", .text = "```\n1702:000000 = 7 # Sky S02 - 7 second interval\n1833:000401 = 7 # HD+ - 7 second interval\n*=7 # Default 7 seconds for all other providers\n```", .status = 0 }, - { .param = "Alternative", .config = "ac", .section = "", .text = "```\n1702:000000 = 10 # Sky S02 - 10 second interval\n1833:000401 = 10 # HD+ - 10 second interval\n*=7 # Default 7 seconds for all other providers\n```", .status = 0 }, - { .param = "Multiple", .config = "ac", .section = "", .text = "```\n0100:000000=10 # Provider 1 - 10 seconds\n0200:000001=8 # Provider 2 - 8 seconds\n0300:000002=12 # Provider 3 - 12 seconds\n*=7 # Default for all others\n```", .status = 0 }, - { .param = "Choosing", .config = "ac", .section = "", .text = "- Typical intervals range from 7 to 10 seconds\n- Shorter intervals (5-7 seconds) provide stricter anti-cascading protection\n- Longer intervals (10-15 seconds) are more lenient but may miss some cascading attempts\n- Consider the normal channel switching behavior of legitimate users", .status = 0 }, - { .param = "Configuration", .config = "ac", .section = "", .text = "1. Start with a default value using the wildcard (*) entry\n2. Add specific entries for high-value providers that need stricter control\n3. Test the configuration to ensure legitimate users aren't affected\n4. Monitor logs for potential cascading attempts", .status = 0 }, - { .param = "Common", .config = "ac", .section = "", .text = "- **1702:000000**: Sky Germany (S02 cards)\n- **1833:000401**: HD+ Germany\n- **0100:000000**: Seca/Mediaguard systems\n- **0500:000000**: Viaccess systems\n- **0D95:000000**: ORF ICE", .status = 0 }, - { .param = "label", .config = "server", .section = "reader", .text = "**🔴 Required parameter**\n\nName for reader.\n\n**Format:**\n```ini\nlabel = name\n```\n\n**Example:**\n```ini\nlabel = easymouse2\n```", .status = 0 }, - { .param = "description", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nDescription of reader (text).\n\n**Format:**\n```ini\ndescription = text\n```\n\n**Example:**\n```ini\ndescription = My main card reader\n```\n\n**Default:**\n```ini\ndescription =\n```", .status = 0 }, - { .param = "enable", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nDeactivate reader.\n\n```ini\nenable = 0 # off\nenable = 1 # on (default)\n```\n\n**Format:**\n```ini\nenable = 0|1\n```\n\n**Example:**\n```ini\nenable = 0\n```\n\n**Default:**\n```ini\nenable = 1\n```", .status = 0 }, - { .param = "protocol", .config = "server", .section = "reader", .text = "**🔴 Required parameter**\n\nReader protocol.\n\n**Values:**\n```ini\nprotocol = mouse # Local cardreader\n = internal # All cardreader with \"device=/dev/sciX\", and internal Coolstream-Reader\n = camd35 # Cascading - camd 3.5-compatible remote server - UDP\n = cs357x # Cascading - camd 3.5-compatible remote server - UDP\n = mp35\n = smartreader\n = serial\n = cs378x # Camd 3.5-compatible remote server - TCP\n = gbox\n = newcamd # newcamd protocol\n = newcamd525\n = newcamd524\n = cccam\n = radegast\n = pcsc\n = constcw\n = sc8in1\n = smargo\n```", .status = 0 }, - { .param = "device", .config = "server", .section = "reader", .text = "**🔴 Required parameter**\n\nDefine local or remote reader.\n\n**Syntax:**\n```ini\ndevice = [;]serial:serialnum|bus:device||,[,]|pcsc|<0|1>|constantcw\n```\n\n**Reader Types:**\n- `SR:` Smartreader+ (default)\n- `SRv2:` Smartreader V2\n- `Infinity:` Infinity USB\n- `TripleP1:` Smargo Triple Reader port 1\n- `TripleP2:` Smargo Triple Reader port 2\n- `TripleP3:` Smargo Triple Reader port 3\n\n**Device Formats:**\n- `bus:device` - Bus name and device name of the smartreader+ (get the name with lsusb 'Bus' and 'Device')\n- `serialnum` - Serial number of Smartreader+ or Infinity USB (get the serial number while starting OSCam)\n- `device` - Device name\n- `device:slot` - Device name and slot number sc8in1 (1-8), only one sc8in1 reader supported\n- `ip|hostname` - IP address or host name\n- `port` - TCP/IP port\n- `lport` - Remapping to local TCP/IP port\n- `PCSC` - Number of PCSC reader, starting with 0. Alternative: select via reader name (part), e.g., \"-1:SCR 3310\" (names of detected readers are shown by \"oscam -d 32\")\n- `0|1` - **For Coolstream HD-1 STB only:** select reader 0 or reader 1\n- `constantcw` - Constant CW file name\n\n**CW File Format:**\n\n*Standard:*\n```\nCAID:Provider ID:Service ID:PMT ID:ECM PID::key (16 Bytes separated by spaces)\n```\nExample:\n```\n1234:123456:1234:2345:3456::00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n```\n\n*Extended OSCam-Format:*\n```\nCAID:Provider ID:Service ID:PMT ID:ECM PID:Video PID:key (16 Bytes separated by spaces)\n```\nExample:\n```\n1234:123456:1234:2345:3456:7890:00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n```\n\n**Examples:**\n```ini\ndevice = /dev/ttyS0 # Reader on COM1 (Linux i386 and Windows)\ndevice = /dev/tts/1 # Reader on COM2 (Linux dbox2 with multicam)\ndevice = /dev/ttyUSB0 # Reader on USB (Linux i386)\ndevice = /dev/ttyUSB0:1 # Slot 1 SC8in1 or MCR 4/8 (Linux i386)\n```\n\n⚠️ **Attention:** Counting begins with 0, that means number of device is one less than number of COM-Port! E.g., ttyS0 = COM1, tts/1 = COM2.", .status = 0 }, - { .param = "ipv4force", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nForce IPv4 connection for this reader even when IPv6 is available.\n\n```ini\nipv4force = 0 # use IPv6 if available (default)\nipv4force = 1 # force IPv4 only\n```\n\n**Format:**\n```ini\nipv4force = 0|1\n```\n\n**Example:**\n```ini\nipv4force = 1\n```\n\n**Default:**\n```ini\nipv4force = 0\n```", .status = 0 }, - { .param = "key", .config = "server", .section = "reader", .text = "**🔵 Parameter depends on setup/program version**\n\nKey for newcamd remote reader encryption.\n\n**Format:**\n```ini\nkey = 14_hex_bytes\n```\n\n**Example:**\n```ini\nkey = 0102030405060708091011121314\n```\n\n**Default:**\n```ini\nkey =\n```", .status = 0 }, - { .param = "user", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nUser for remote reader (name).\n\n**Format:**\n```ini\nuser = username\n```\n\n**Example:**\n```ini\nuser = username\n```\n\n**Default:**\n```ini\nuser =\n```", .status = 0 }, - { .param = "password", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nPassword for remote reader.\n\n**Format:**\n```ini\npassword = secret\n```\n\n**Example:**\n```ini\npassword = secret\n```\n\n**Default:**\n```ini\npassword =\n```", .status = 0 }, - { .param = "pincode", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nPincode for **Conax, Cryptoworks and Viaccess** SCs.\n\n**Example:**\n```ini\npincode = 1234\n```\n\n**Default:**\n```ini\npincode =\n```", .status = 0 }, - { .param = "gbox_max_distance", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nMaximum distance to receive peer cards.\n\n**Format:**\n```ini\ngbox_max_distance = distance\n```\n\n**Example:**\n```ini\ngbox_max_distance = 3\n```\n\n**Default:**\n```ini\ngbox_max_distance = 2\n```", .status = 0 }, - { .param = "gbox_max_ecm_send", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nSend ECM to max `` peer cards.\n\n**Format:**\n```ini\ngbox_max_ecm_send = number\n```\n\n**Example:**\n```ini\ngbox_max_ecm_send = 10\n```\n\n**Default:**\n```ini\ngbox_max_ecm_send = 5\n```", .status = 0 }, - { .param = "gbox_reshare", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nShare-Level of local card(s).\n\n```ini\ngbox_reshare = 0 # None of your local cards send to peer\ngbox_reshare = 1 # Local cards send to direct peer only\ngbox_reshare = 2 # Local cards send to direct peer and his direct peer(s)\n```\n\n**Format:**\n```ini\ngbox_reshare = 0|1|2|3|4|5\n```\n\n**Example:**\n```ini\ngbox_reshare = 1\n```\n\n**Default:**\n```ini\ngbox_reshare = 2\n```", .status = 0 }, - { .param = "cccreshare", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nReshare level of CCC proxy cards to be sent into gbox network.\n\n```ini\ncccreshare = -1 # No resharing (default)\ncccreshare = 0 # Reshare for direct peer only\ncccreshare = 1 # Reshare for direct peer plus next level\ncccreshare = x # Resharing for direct peer plus x share level\n```\n\n**Format:**\n```ini\ncccreshare = -1|0|1|...\n```\n\n**Example:**\n```ini\ncccreshare = 1\n```\n\n**Default:**\n```ini\ncccreshare = -1\n```", .status = 0 }, - { .param = "force_remm", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nForce remote EMM.\n\n```ini\nforce_remm = 0 # Disabled (default)\nforce_remm = 1 # Enabled\n```\n\n⚠️ **Attention: Use only to activate a card or if card entitlements are expired**\n\n**Format:**\n```ini\nforce_remm = 0|1\n```\n\n**Example:**\n```ini\nforce_remm = 1\n```\n\n**Default:**\n```ini\nforce_remm = 0\n```", .status = 0 }, - { .param = "ccc_gbx_reshare_ident", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nDefine CAID and provider of cccam cards you want to send to peer.\n\n**Syntax:**\n```ini\nccc_gbx_reshare_ident = :[,prov]...[;:[,prov]...]...\n```\n\n**Example:**\n```ini\nccc_gbx_reshare_ident = 0100:123456,234567;0200:345678,456789\n = # Blank, all available cccam cards are sent to peer (default)\n```", .status = 0 }, - { .param = "send_offline_cmd", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nSend offline cmd HERE to peers offline.\n\n```ini\nsend_offline_cmd = 0 # Default\nsend_offline_cmd = 1 # Enabled\n```\n\n**Format:**\n```ini\nsend_offline_cmd = 0|1\n```\n\n**Example:**\n```ini\nsend_offline_cmd = 1\n```\n\n**Default:**\n```ini\nsend_offline_cmd = 0\n```", .status = 0 }, - { .param = "readnano", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nWrite file (usually a copy of a file saved by `savenano`) to your smartcard. If no path is specified, the specified file is searched for in the configuration directory. Only valid for physical readers!\n\n**Examples:**\n```ini\nreadnano = write.emm\n = /var/oscam/write.emm\n = # Blank (default)\n```", .status = 0 }, - { .param = "services", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n⚠️ **Attention:** If loadbalancing is enabled in `oscam.conf [global]` among `lb_mode`, then there may be **no entries**!\n\n⚠️ **Attention:** The number of services that will be considered based reader, is limited to 64, or 64 times [service-name][CAID][provid][srvid]!\n\nAssignment to service group. This requires an `oscam.services` file to be present.\n\n**Logic (in this order):**\n1. If the field is empty (or invalid), the request is allowed.\n2. When a negative service (i.e., those with \"!\") is applicable, the request is rejected.\n3. If a positive service is applicable or there is no positive service, the request is allowed.\n4. If none of the previous points, the request is rejected.\n\nThis means that negative services are only necessary in individual cases - when services has positive entries, but you want to exclude some. This is not recommended, because misconfiguration can occur easily. Instead, create an additional service that contains all the relevant channels.\n\n**Syntax:**\n```ini\nservices = [!]service[,[!]service]...\n = # Blank (default)\n```", .status = 0 }, - { .param = "lb_whitelist_services", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nReader assignment to service group for channels which may never be blocked by the loadbalancer to the reader.\n\n**Syntax:**\n```ini\nlb_whitelist_services = ,...\n```\n\n**Default:**\n```ini\nlb_whitelist_services =\n```", .status = 0 }, - { .param = "inactivitytimeout", .config = "server", .section = "reader", .text = "**🔵 Parameter depends on setup/program version**\n\nInactivity timeout in seconds.\n\n```ini\ninactivitytimeout = -1 # Reconnect on network failure for newcamd based readers, even in idle\ninactivitytimeout = 0 # Default\n```\n\n**Format:**\n```ini\ninactivitytimeout = -1|0|seconds\n```\n\n**Example:**\n```ini\ninactivitytimeout = 300\n```\n\n**Default:**\n```ini\ninactivitytimeout = 0\n```", .status = 0 }, - { .param = "reconnecttimeout", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nReconnect from a remote reader, if missing answers in seconds.\n\n**Format:**\n```ini\nreconnecttimeout = seconds\n```\n\n**Example:**\n```ini\nreconnecttimeout = 20\n```\n\n**Default:**\n```ini\nreconnecttimeout =\n```", .status = 0 }, - { .param = "reconnectdelay", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nDelay in milliseconds before reconnecting to the remote server after a connection loss.\n\n**Format:**\n```ini\nreconnectdelay = milliseconds\n```\n\n**Example:**\n```ini\nreconnectdelay = 30000\n```\n\n**Default:**\n```ini\nreconnectdelay = 60000\n```", .status = 0 }, - { .param = "resetcycle", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nNumber of ECMs until SC reset is performed.\n\n⚠️ **Hint:** Valid for physical readers only!\n\n**Format:**\n```ini\nresetcycle = count\n```\n\n**Example:**\n```ini\nresetcycle = 5\n```\n\n**Default:**\n```ini\nresetcycle = 0\n```", .status = 0 }, - { .param = "disableserverfilter", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nIgnore CAID and ident settings of reader due to faulty clients.\n\n```ini\ndisableserverfilter = 0 # Not ignore (default)\ndisableserverfilter = 1 # Ignore\n```\n\n**Format:**\n```ini\ndisableserverfilter = 0|1\n```\n\n**Example:**\n```ini\ndisableserverfilter = 1\n```\n\n**Default:**\n```ini\ndisableserverfilter = 0\n```", .status = 0 }, - { .param = "connectoninit", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nAllow newcamd connections to be established on startup although there isn't a request yet.\n\n```ini\nconnectoninit = 0 # Default\nconnectoninit = 1 # Allow connection on init\n```\n\n**Format:**\n```ini\nconnectoninit = 0|1\n```\n\n**Example:**\n```ini\nconnectoninit = 1\n```\n\n**Default:**\n```ini\nconnectoninit = 0\n```", .status = 0 }, - { .param = "keepalive", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nKeep connection alive.\n\n```ini\nkeepalive = 0 # Always on if cacheex reader type (default)\nkeepalive = 1 # Allow cs378x TCP socket to be always connected\n```\n\n**Format:**\n```ini\nkeepalive = 0|1\n```\n\n**Example:**\n```ini\nkeepalive = 1\n```\n\n**Default:**\n```ini\nkeepalive = 0\n```", .status = 0 }, - { .param = "smargopatch", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nEnable workaround for smartreader+ and reader until native mode works.\n\n```ini\nsmargopatch = 0 # Disabled (default)\nsmargopatch = 1 # Enabled\n```\n\n**Format:**\n```ini\nsmargopatch = 0|1\n```\n\n**Example:**\n```ini\nsmargopatch = 1\n```\n\n**Default:**\n```ini\nsmargopatch = 0\n```", .status = 0 }, - { .param = "autospeed", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nAuto speed detection.\n\n```ini\nautospeed = 0 # Disabled\nautospeed = 1 # Enabled (default) - Sets mhz according to ATR\n```\n\nCurrently only used for smartreader, smargo protocol and Dreambox-readers internal protocol. Other readers will be adapted to use this parameter as well.\n\nIf you want to overclock your card, set autospeed to 0.\n\n**Format:**\n```ini\nautospeed = 0|1\n```\n\n**Example:**\n```ini\nautospeed = 0\n```\n\n**Default:**\n```ini\nautospeed = 1\n```", .status = 0 }, - { .param = "sc8in1_dtrrts_patch", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nEnable fix for SC8in1/MCR DTR/RTS kernel bug.\n\n```ini\nsc8in1_dtrrts_patch = 0 # Disabled (default)\nsc8in1_dtrrts_patch = 1 # Enabled\n```\n\n**Format:**\n```ini\nsc8in1_dtrrts_patch = 0|1\n```\n\n**Example:**\n```ini\nsc8in1_dtrrts_patch = 1\n```\n\n**Default:**\n```ini\nsc8in1_dtrrts_patch = 0\n```", .status = 0 }, - { .param = "fallback", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nDefine reader as fallback. Standard and fallback reader must have the same group (see **group** parameter)!\n\n```ini\nfallback = 0 # No fallback reader (default)\nfallback = 1 # Fallback reader\n```\n\n**Format:**\n```ini\nfallback = 0|1\n```\n\n**Example:**\n```ini\nfallback = 1\n```\n\n**Default:**\n```ini\nfallback = 0\n```", .status = 0 }, - { .param = "fallback_percaid", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nUse reader as fallback for defined CAIDs only. Two digit wildcards CAIDs are possible. `fallback_percaid` overrules `fallback`.\n\n**Syntax:**\n```ini\nfallback_percaid = [:[,ident]]...[;[:[,ident]]...]...\n```\n\n**Example:**\n```ini\nfallback_percaid = 1234:234567;10:345678\n```\n\n**Default:**\n```ini\nfallback_percaid =\n```", .status = 0 }, - { .param = "localcards", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nUse this reader (for defined CAIDs only) as \"local\" in LB/reader selection. It will be handled as a local reader per LB and preferlocalcards settings. In this way, we can consider a network reader as local, like we had a cardreader.\n\n**Syntax:**\n```ini\nlocalcards = [:[,ident]]...[;[:[,ident]]...]...\n```", .status = 0 }, - { .param = "disablecrccws_only_for", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**Syntax:**\n```ini\ndisablecrccws_only_for = CAID:PROVID;CAID:PROVID\n```\n\n**Example:**\n```ini\ndisablecrccws_only_for = 0500:032830;098C:000000\n```", .status = 0 }, - { .param = "cacheex", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\nEnable cache exchange mode for camd 3.5x and CCcam protocol.\n\n```ini\ncacheex = 0 # Disabled (default)\ncacheex = 1 # Enable cache exchange pull mode\ncacheex = 2 # Enable cache exchange push mode\ncacheex = 3 # Enable cache exchange reverse push mode\n```\n\n📋 See also on `oscam.user`!\n\n⚠️ Identical cache exchange modes must be set on local OSCam server and remote OSCam user account!\n\n**Format:**\n```ini\ncacheex = 0|1|2|3\n```\n\n**Example:**\n```ini\ncacheex = 2\n```\n\n**Default:**\n```ini\ncacheex = 0\n```\n\n#### cacheex modes\n\n#### cacheex = 1 - cachepull\n\n**Situation:**\n- OSCam A reader1 has `cacheex = 1`\n- OSCam B account1 has `cacheex = 1`\n\nOSCam A gets an ECM request, reader1 sends this request to OSCam B.\n\nOSCam B checks his cache:\n- Not found in cache: return NOK\n- Found in cache: return OK+CW\n- Not found in cache, but found pending request: wait `cacheexwaittime` in `oscam.conf [global]` and check again. OSCam B never requests new EMMs.\n\n**CW-flow:** B → A\n\n#### cacheex = 2 - cachepush\n\n**Situation:**\n- OSCam A reader1 has `cacheex = 2`\n- OSCam B account1 has `cacheex = 2`\n\nIf OSCam B gets a CW, it's pushed to OSCam A. Reader has normal functionality and can request ECMs.\n\n- Problem: OSCam can only push CWs if OSCam A is connected\n- Problem or feature?: OSCam A reader can request ECMs from OSCam B\n\n**CW-flow:** B → A\n\n#### cacheex = 3 - reversecachepush\n\n**Situation:**\n- OSCam A reader1 has `cacheex = 3`\n\nIf OSCam A gets a CW, it's pushed to OSCam B. OSCam A never requests new ECMs.\n\n**CW-flow:** A → B", .status = 0 }, - { .param = "cacheex_maxhop", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\nDefine maximum hops for cache exchange.\n\n**Format:**\n```ini\ncacheex_maxhop = hops\n```\n\n**Example:**\n```ini\ncacheex_maxhop = 5\n```\n\n**Default:**\n```ini\ncacheex_maxhop = 10\n```", .status = 0 }, - { .param = "cacheex_maxhop_lg", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nDefine a maxhop for lg-flagged CWs for push/receive, to allow a higher maxhop than for non-flagged CWs.\n\n```ini\ncacheex_maxhop_lg = 0 # Use value of cacheex_maxhop (default)\ncacheex_maxhop_lg = 1 to 10 # Set maxhop (if value is lower than cacheex_maxhop, value of cacheex_maxhop is used)\n```\n\n**Format:**\n```ini\ncacheex_maxhop_lg = 0-10\n```\n\n**Example:**\n```ini\ncacheex_maxhop_lg = 5\n```\n\n**Default:**\n```ini\ncacheex_maxhop_lg = 0\n```", .status = 0 }, - { .param = "cacheex_ecm_filter", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\nCacheEx ECM filter for this reader. Defines which CAIDs/providers/services are allowed for cache exchange.\n\n**Format:**\n```ini\ncacheex_ecm_filter = [caid][&mask][@provid][$servid],n\n```\n\n**Example:**\n```ini\ncacheex_ecm_filter = 1234@000001,1234@000002\n```\n\n**Default:**\n```ini\ncacheex_ecm_filter =\n```", .status = 0 }, - { .param = "cacheex_allow_request", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\nAllow ECM requests from this CacheEx reader.\n\n```ini\ncacheex_allow_request = 0 # ECM requests disabled (default)\ncacheex_allow_request = 1 # ECM requests allowed\n```\n\n**Format:**\n```ini\ncacheex_allow_request = 0|1\n```\n\n**Example:**\n```ini\ncacheex_allow_request = 1\n```\n\n**Default:**\n```ini\ncacheex_allow_request = 0\n```", .status = 0 }, - { .param = "cacheex_drop_csp", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\nDrop CWs received via CSP (Cardservproxy protocol) for this reader.\n\n```ini\ncacheex_drop_csp = 0 # accept CSP CWs (default)\ncacheex_drop_csp = 1 # drop CSP CWs\n```\n\n**Format:**\n```ini\ncacheex_drop_csp = 0|1\n```\n\n**Example:**\n```ini\ncacheex_drop_csp = 1\n```\n\n**Default:**\n```ini\ncacheex_drop_csp = 0\n```", .status = 0 }, - { .param = "cacheex_allow_filter", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\nAllow this reader to set CacheEx ECM filters remotely.\n\n```ini\ncacheex_allow_filter = 0 # remote filter setting disabled\ncacheex_allow_filter = 1 # remote filter setting allowed (default)\n```\n\n**Format:**\n```ini\ncacheex_allow_filter = 0|1\n```\n\n**Example:**\n```ini\ncacheex_allow_filter = 0\n```\n\n**Default:**\n```ini\ncacheex_allow_filter = 1\n```", .status = 0 }, - { .param = "cacheex_allow_maxhop", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nSet maxhop settings remotely, if remote reader/user has `cacheex_allow_maxhop = 1`.\n\n```ini\ncacheex_allow_maxhop = 0 # Opt-in (default)\ncacheex_allow_maxhop = 1 # Allow\n```\n\n**Format:**\n```ini\ncacheex_allow_maxhop = 0|1\n```\n\n**Example:**\n```ini\ncacheex_allow_maxhop = 1\n```\n\n**Default:**\n```ini\ncacheex_allow_maxhop = 0\n```", .status = 0 }, - { .param = "cacheex_block_fakecws", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\nBlock fake CWs for this reader.\n\n```ini\ncacheex_block_fakecws = 0 # allow all CWs (default)\ncacheex_block_fakecws = 1 # block fake CWs\n```\n\n**Format:**\n```ini\ncacheex_block_fakecws = 0|1\n```\n\n**Example:**\n```ini\ncacheex_block_fakecws = 1\n```\n\n**Default:**\n```ini\ncacheex_block_fakecws = 0\n```", .status = 0 }, - { .param = "cacheex_cw_check_for_push", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nPush only when `cacheex_cw_check` counter reached. Localgenerated-flagged CWs are always pushed out.\n\n```ini\ncacheex_cw_check_for_push = 0 # Opt-in (default)\ncacheex_cw_check_for_push = 1 # Enable\n```\n\n**Format:**\n```ini\ncacheex_cw_check_for_push = 0|1\n```\n\n**Example:**\n```ini\ncacheex_cw_check_for_push = 1\n```\n\n**Default:**\n```ini\ncacheex_cw_check_for_push = 0\n```", .status = 0 }, - { .param = "cacheex_lg_only_remote_settings", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nPossibility to deny cacheex-receiver/client (cx2: user / cx3: reader) to overwrite the following settings at cacheex-sending-instance:\n- `cacheex_localgenerated_only`\n- `cacheex_lg_only_tab`\n\nIt makes sense if you want to force your local settings. If the user/reader isn't allowed to overwrite your values:\n- It is still possible for the cacheex-receiver to set `cacheex_localgenerated_only=1`, if the user/reader defines `cacheex_localgenerated_only_in=1`; but it is only at cacheex-sending-instance possible to disable it\n- It is still possible for the cacheex-receiver to add `cacheex_lg_only_tab`, if the user/reader defines `cacheex_lg_only_in_tab=1234,1337`; but it is only merged to the sender-instance `cacheex_lg_only_tab` values\n\nIf `cacheex_lg_only_remote_settings` in `oscam.conf` is enabled, the user/reader-settings are ignored.\n\n```ini\ncacheex_lg_only_remote_settings = 0 # Opt-out (default)\ncacheex_lg_only_remote_settings = 1 # Deny remote overwrite\n```\n\n**Format:**\n```ini\ncacheex_lg_only_remote_settings = 0|1\n```\n\n**Example:**\n```ini\ncacheex_lg_only_remote_settings = 1\n```\n\n**Default:**\n```ini\ncacheex_lg_only_remote_settings = 0\n```", .status = 0 }, - { .param = "cacheex_localgenerated_only", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nForward only CWs which are flagged as localgenerated.\n\n```ini\ncacheex_localgenerated_only = 0 # Opt-in (default)\ncacheex_localgenerated_only = 1 # Enable\n```\n\n**Format:**\n```ini\ncacheex_localgenerated_only = 0|1\n```\n\n**Example:**\n```ini\ncacheex_localgenerated_only = 1\n```\n\n**Default:**\n```ini\ncacheex_localgenerated_only = 0\n```", .status = 0 }, - { .param = "cacheex_localgenerated_only_caid", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nCAID table for localgenerated-only filter. Deprecated: use cacheex_lg_only_tab instead.\n\n**Format:**\n```ini\ncacheex_localgenerated_only_caid = CAID1[,CAID2]...\n```\n\n**Example:**\n```ini\ncacheex_localgenerated_only_caid = 0100,0500,1702\n```\n\n**Default:**\n```ini\ncacheex_localgenerated_only_caid =\n```", .status = 0 }, - { .param = "cacheex_lg_only_tab", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nForward only CWs which are lg-flagged for this list of caid/provid(s).\n\nIf provid FFFFFE is set, all provids for this caid are valid!\n\n**Syntax:**\n```ini\ncacheex_lg_only_tab = caid1:provid1[,provid2];caid2:provid1;\n```", .status = 0 }, - { .param = "cacheex_lg_only_in_aio_only", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nUse drop lg-only settings (`cacheex_localgenerated_only_in` & `cacheex_lg_only_in_tab`) only if peer is detected as cx-aio-patched or svn >= 11588.\n\n```ini\ncacheex_lg_only_in_aio_only = 0 # Opt-in (default)\ncacheex_lg_only_in_aio_only = 1 # Enable\n```\n\n**Format:**\n```ini\ncacheex_lg_only_in_aio_only = 0|1\n```\n\n**Example:**\n```ini\ncacheex_lg_only_in_aio_only = 1\n```\n\n**Default:**\n```ini\ncacheex_lg_only_in_aio_only = 0\n```", .status = 0 }, - { .param = "cacheex_localgenerated_only_in", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nDrop incoming CWs which are NOT flagged as localgenerated.\n\n```ini\ncacheex_localgenerated_only_in = 0 # Opt-in (default)\ncacheex_localgenerated_only_in = 1 # Enable\n```\n\n**Format:**\n```ini\ncacheex_localgenerated_only_in = 0|1\n```\n\n**Example:**\n```ini\ncacheex_localgenerated_only_in = 1\n```\n\n**Default:**\n```ini\ncacheex_localgenerated_only_in = 0\n```", .status = 0 }, - { .param = "cacheex_localgenerated_only_in_caid", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nCAID table for incoming localgenerated-only filter. Deprecated: use cacheex_lg_only_in_tab instead.\n\n**Format:**\n```ini\ncacheex_localgenerated_only_in_caid = CAID1[,CAID2]...\n```\n\n**Example:**\n```ini\ncacheex_localgenerated_only_in_caid = 0100,0500,1702\n```\n\n**Default:**\n```ini\ncacheex_localgenerated_only_in_caid =\n```", .status = 0 }, - { .param = "cacheex_lg_only_in_tab", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nAllow incoming CWs only if they are lg-flagged for this list of caid/provid(s).\n\nIf provid FFFFFE is set, all provids for this caid are valid!\n\n**Syntax:**\n```ini\ncacheex_lg_only_in_tab = caid1:provid1[,provid2];caid2:provid1;\n```", .status = 0 }, - { .param = "cacheex_nopushafter", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nDon't forward CWs from local/proxy-reader via CacheEx, if the defined time_in_ms for the CAID is reached.\n\n**Syntax:**\n```ini\ncacheex_nopushafter = CAID:time_in_ms[,n]\n```", .status = 0 }, - { .param = "caid", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nDefine and mapping of CAIDs for reader.\n\n**Syntax:**\n```ini\ncaid = [&][:][,[&][:]]...\n```\n\n**Examples:**\n```ini\ncaid = 0100\ncaid = 0200&ffee:0300\ncaid = 0400&ff00:0500,0600\ncaid = 0702,0722\ncaid = 0702&ffdf # Shortcut for the example above\n```\n\n**Default:** All CAIDs with mask FFFF", .status = 0 }, - { .param = "atr", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nSet a custom ATR (Answer To Reset) for the reader. Override the automatic ATR detection.\n\n**Format:**\n```ini\natr = hex_bytes\n```\n\n**Example:**\n```ini\natr = 3B9F21E49067534C000000280F28000069FF6500\n```\n\n**Default:**\n```ini\natr =\n```", .status = 0 }, - { .param = "boxid", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nNDS receiver box ID.\n\n**Example:**\n```ini\nboxid = 12345678\n```\n\n**Default:**\n```ini\nboxid =\n```", .status = 0 }, - { .param = "tongfang3_calibsn", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_TONGFANG` compilation flag)**\n\nCalibration serial number for Tongfang v3 readers. 4 bytes in hexadecimal.\n\n**Format:**\n```ini\ntongfang3_calibsn = hex_bytes\n```\n\n**Example:**\n```ini\ntongfang3_calibsn = 12345678\n```\n\n**Default:**\n```ini\ntongfang3_calibsn =\n```", .status = 0 }, - { .param = "tongfang_boxid", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_TONGFANG` compilation flag)**\n\nBox ID for Tongfang readers. 4 bytes in hexadecimal.\n\n**Format:**\n```ini\ntongfang_boxid = hex_bytes\n```\n\n**Example:**\n```ini\ntongfang_boxid = 12345678\n```\n\n**Default:**\n```ini\ntongfang_boxid =\n```", .status = 0 }, - { .param = "stbid", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_TONGFANG` compilation flag)**\n\nSTB ID for Tongfang v3 readers. 8 bytes in hexadecimal.\n\n**Format:**\n```ini\nstbid = hex_bytes\n```\n\n**Example:**\n```ini\nstbid = 0102030405060708\n```\n\n**Default:**\n```ini\nstbid =\n```", .status = 0 }, - { .param = "tongfang3_deskey", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_TONGFANG` compilation flag)**\n\nDES key for Tongfang v3 readers. 8 bytes in hexadecimal.\n\n**Format:**\n```ini\ntongfang3_deskey = hex_bytes\n```\n\n**Example:**\n```ini\ntongfang3_deskey = 0102030405060708\n```\n\n**Default:**\n```ini\ntongfang3_deskey =\n```", .status = 0 }, - { .param = "boxkey", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nBox key for Nagravision SCs / CAM key for Irdeto SCs / sessionkey for Seca SCs / CamID for Viaccess.\n\n**Default:**\n```ini\nboxkey =\n```", .status = 0 }, - { .param = "rsakey", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nRSA key for Nagravision/Tiger SCs / CAM key data for Irdeto SCs, Conax SCs.\n\n**Default:**\n```ini\nrsakey =\n```", .status = 0 }, - { .param = "cwpkkey", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nCWPK (Control Word Protection Key) for Nagra readers.\n\n**Format:**\n```ini\ncwpkkey = index:hex_bytes\n```\n\n**Example:**\n```ini\ncwpkkey = 0:0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncwpkkey =\n```", .status = 0 }, - { .param = "deskey", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nDES key for the reader in hexadecimal format.\n\n**Format:**\n```ini\ndeskey = hex_bytes\n```\n\n**Example:**\n```ini\ndeskey = 0102030405060708090A0B0C0D0E\n```\n\n**Default:**\n```ini\ndeskey =\n```", .status = 0 }, - { .param = "mod1", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nModulus 1 for Nagra Merlin readers. 112 bytes in hexadecimal.\n\n**Format:**\n```ini\nmod1 = hex_bytes\n```\n\n**Example:**\n```ini\nmod1 = 0102030405...\n```\n\n**Default:**\n```ini\nmod1 =\n```", .status = 0 }, - { .param = "idird", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nIRD ID for Nagra Merlin readers. 4 bytes in hexadecimal.\n\n**Format:**\n```ini\nidird = hex_bytes\n```\n\n**Example:**\n```ini\nidird = 12345678\n```\n\n**Default:**\n```ini\nidird =\n```", .status = 0 }, - { .param = "cmd0eprov", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nProvider ID for CMD0E command. Use only if CMD0E needs a ProvID other than the system ID.\n\n**Format:**\n```ini\ncmd0eprov = hex_bytes\n```\n\n**Example:**\n```ini\ncmd0eprov = 1234\n```\n\n**Default:**\n```ini\ncmd0eprov =\n```", .status = 0 }, - { .param = "mod2", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nModulus 2 for Nagra Merlin readers. 112 bytes in hexadecimal.\n\n**Format:**\n```ini\nmod2 = hex_bytes\n```\n\n**Example:**\n```ini\nmod2 = 0102030405...\n```\n\n**Default:**\n```ini\nmod2 =\n```", .status = 0 }, - { .param = "key3588", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nKey 3588 for Nagra Merlin readers. 136 bytes in hexadecimal.\n\n**Format:**\n```ini\nkey3588 = hex_bytes\n```\n\n**Example:**\n```ini\nkey3588 = 0102030405...\n```\n\n**Default:**\n```ini\nkey3588 =\n```", .status = 0 }, - { .param = "key3460", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nKey 3460 for Nagra Merlin readers. 96 bytes in hexadecimal.\n\n**Format:**\n```ini\nkey3460 = hex_bytes\n```\n\n**Example:**\n```ini\nkey3460 = 0102030405...\n```\n\n**Default:**\n```ini\nkey3460 =\n```", .status = 0 }, - { .param = "key3310", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nKey 3310 for Nagra Merlin readers. 16 bytes in hexadecimal.\n\n**Format:**\n```ini\nkey3310 = hex_bytes\n```\n\n**Example:**\n```ini\nkey3310 = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\nkey3310 =\n```", .status = 0 }, - { .param = "data50", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nData 50 for Nagra Merlin readers. 80 bytes in hexadecimal.\n\n**Format:**\n```ini\ndata50 = hex_bytes\n```\n\n**Example:**\n```ini\ndata50 = 0102030405...\n```\n\n**Default:**\n```ini\ndata50 =\n```", .status = 0 }, - { .param = "mod50", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nModulus 50 for Nagra Merlin readers. 80 bytes in hexadecimal.\n\n**Format:**\n```ini\nmod50 = hex_bytes\n```\n\n**Example:**\n```ini\nmod50 = 0102030405...\n```\n\n**Default:**\n```ini\nmod50 =\n```", .status = 0 }, - { .param = "nuid", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nNUID (Network Unique Identifier) for Nagra Merlin readers. 4 bytes in hexadecimal.\n\n**Format:**\n```ini\nnuid = hex_bytes\n```\n\n**Example:**\n```ini\nnuid = 12345678\n```\n\n**Default:**\n```ini\nnuid =\n```", .status = 0 }, - { .param = "forcepair", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nForce pairing byte for Nagra Merlin readers. Use 00 for global pairing.\n\n**Format:**\n```ini\nforcepair = hex_byte\n```\n\n**Example:**\n```ini\nforcepair = 00\n```\n\n**Default:**\n```ini\nforcepair =\n```", .status = 0 }, - { .param = "otpcsc", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nForce OTP CSC (Card Status Code) for Nagra Merlin readers.\n\n**Format:**\n```ini\notpcsc = hex_bytes\n```\n\n**Example:**\n```ini\notpcsc = 1234\n```\n\n**Default:**\n```ini\notpcsc =\n```", .status = 0 }, - { .param = "otacsc", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nForce OTA CSC (Card Status Code) for Nagra Merlin readers.\n\n**Format:**\n```ini\notacsc = hex_bytes\n```\n\n**Example:**\n```ini\notacsc = 1234\n```\n\n**Default:**\n```ini\notacsc =\n```", .status = 0 }, - { .param = "cwpkcaid", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nCAID for BoxEMM CWPK for Nagra Merlin readers.\n\n**Format:**\n```ini\ncwpkcaid = hex_bytes\n```\n\n**Example:**\n```ini\ncwpkcaid = 1834\n```\n\n**Default:**\n```ini\ncwpkcaid =\n```", .status = 0 }, - { .param = "cwekey0", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nCWPK0 (Control Word Protection Key) for Nagra Merlin readers. 16 bytes in hexadecimal.\n\n**Format:**\n```ini\ncwekey0 = hex_bytes\n```\n\n**Example:**\n```ini\ncwekey0 = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncwekey0 =\n```", .status = 0 }, - { .param = "cwekey1", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nCWPK1 (Control Word Protection Key) for Nagra Merlin readers. 16 bytes in hexadecimal.\n\n**Format:**\n```ini\ncwekey1 = hex_bytes\n```\n\n**Example:**\n```ini\ncwekey1 = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncwekey1 =\n```", .status = 0 }, - { .param = "cwekey2", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nCWPK2 (Control Word Protection Key) for Nagra Merlin readers. 16 bytes in hexadecimal.\n\n**Format:**\n```ini\ncwekey2 = hex_bytes\n```\n\n**Example:**\n```ini\ncwekey2 = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncwekey2 =\n```", .status = 0 }, - { .param = "cwekey3", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nCWPK3 (Control Word Protection Key) for Nagra Merlin readers. 16 bytes in hexadecimal.\n\n**Format:**\n```ini\ncwekey3 = hex_bytes\n```\n\n**Example:**\n```ini\ncwekey3 = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncwekey3 =\n```", .status = 0 }, - { .param = "cwekey4", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nCWPK4 (Control Word Protection Key) for Nagra Merlin readers. 16 bytes in hexadecimal.\n\n**Format:**\n```ini\ncwekey4 = hex_bytes\n```\n\n**Example:**\n```ini\ncwekey4 = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncwekey4 =\n```", .status = 0 }, - { .param = "cwekey5", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nCWPK5 (Control Word Protection Key) for Nagra Merlin readers. 16 bytes in hexadecimal.\n\n**Format:**\n```ini\ncwekey5 = hex_bytes\n```\n\n**Example:**\n```ini\ncwekey5 = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncwekey5 =\n```", .status = 0 }, - { .param = "cwekey6", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nCWPK6 (Control Word Protection Key) for Nagra Merlin readers. 16 bytes in hexadecimal.\n\n**Format:**\n```ini\ncwekey6 = hex_bytes\n```\n\n**Example:**\n```ini\ncwekey6 = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncwekey6 =\n```", .status = 0 }, - { .param = "cwekey7", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nCWPK7 (Control Word Protection Key) for Nagra Merlin readers. 16 bytes in hexadecimal.\n\n**Format:**\n```ini\ncwekey7 = hex_bytes\n```\n\n**Example:**\n```ini\ncwekey7 = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncwekey7 =\n```", .status = 0 }, - { .param = "cwekey8", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nCWPK8 (Control Word Protection Key) for Nagra Merlin readers. 16 bytes in hexadecimal.\n\n**Format:**\n```ini\ncwekey8 = hex_bytes\n```\n\n**Example:**\n```ini\ncwekey8 = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncwekey8 =\n```", .status = 0 }, - { .param = "cwekey9", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nCWPK9 (Control Word Protection Key) for Nagra Merlin readers. 16 bytes in hexadecimal.\n\n**Format:**\n```ini\ncwekey9 = hex_bytes\n```\n\n**Example:**\n```ini\ncwekey9 = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncwekey9 =\n```", .status = 0 }, - { .param = "cwekey10", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nCWPK10 (Control Word Protection Key) for Nagra Merlin readers. 16 bytes in hexadecimal.\n\n**Format:**\n```ini\ncwekey10 = hex_bytes\n```\n\n**Example:**\n```ini\ncwekey10 = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncwekey10 =\n```", .status = 0 }, - { .param = "cwekey11", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nCWPK11 (Control Word Protection Key) for Nagra Merlin readers. 16 bytes in hexadecimal.\n\n**Format:**\n```ini\ncwekey11 = hex_bytes\n```\n\n**Example:**\n```ini\ncwekey11 = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncwekey11 =\n```", .status = 0 }, - { .param = "cwekey12", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nCWPK12 (Control Word Protection Key) for Nagra Merlin readers. 16 bytes in hexadecimal.\n\n**Format:**\n```ini\ncwekey12 = hex_bytes\n```\n\n**Example:**\n```ini\ncwekey12 = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncwekey12 =\n```", .status = 0 }, - { .param = "cwekey13", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nCWPK13 (Control Word Protection Key) for Nagra Merlin readers. 16 bytes in hexadecimal.\n\n**Format:**\n```ini\ncwekey13 = hex_bytes\n```\n\n**Example:**\n```ini\ncwekey13 = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncwekey13 =\n```", .status = 0 }, - { .param = "cwekey14", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nCWPK14 (Control Word Protection Key) for Nagra Merlin readers. 16 bytes in hexadecimal.\n\n**Format:**\n```ini\ncwekey14 = hex_bytes\n```\n\n**Example:**\n```ini\ncwekey14 = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncwekey14 =\n```", .status = 0 }, - { .param = "cwekey15", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nCWPK15 (Control Word Protection Key) for Nagra Merlin readers. 16 bytes in hexadecimal.\n\n**Format:**\n```ini\ncwekey15 = hex_bytes\n```\n\n**Example:**\n```ini\ncwekey15 = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncwekey15 =\n```", .status = 0 }, - { .param = "cwekey16", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nCWPK16 (Control Word Protection Key) for Nagra Merlin readers. 16 bytes in hexadecimal.\n\n**Format:**\n```ini\ncwekey16 = hex_bytes\n```\n\n**Example:**\n```ini\ncwekey16 = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncwekey16 =\n```", .status = 0 }, - { .param = "forcecwswap", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nForce CW (Control Word) swap for Nagra Merlin readers.\n\n```ini\nforcecwswap = 0 # disabled (default)\nforcecwswap = 1 # force CW swap\n```\n\n**Format:**\n```ini\nforcecwswap = 0|1\n```\n\n**Example:**\n```ini\nforcecwswap = 1\n```\n\n**Default:**\n```ini\nforcecwswap = 0\n```", .status = 0 }, - { .param = "evensa", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nForce even SA (Subscriber Address) for Nagra Merlin readers.\n\n```ini\nevensa = 0 # disabled (default)\nevensa = 1 # force even SA\n```\n\n**Format:**\n```ini\nevensa = 0|1\n```\n\n**Example:**\n```ini\nevensa = 1\n```\n\n**Default:**\n```ini\nevensa = 0\n```", .status = 0 }, - { .param = "forceemmg", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nForce EMMs with tag 0x82 (global EMMs) for Nagra Merlin readers.\n\n```ini\nforceemmg = 0 # disabled (default)\nforceemmg = 1 # force 0x82 EMMs\n```\n\n**Format:**\n```ini\nforceemmg = 0|1\n```\n\n**Example:**\n```ini\nforceemmg = 1\n```\n\n**Default:**\n```ini\nforceemmg = 0\n```", .status = 0 }, - { .param = "cwpkota", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nEnable OTA (Over-The-Air) CWPK updates for Nagra Merlin readers.\n\n```ini\ncwpkota = 0 # OTA CWPK disabled (default)\ncwpkota = 1 # OTA CWPK enabled\n```\n\n**Format:**\n```ini\ncwpkota = 0|1\n```\n\n**Example:**\n```ini\ncwpkota = 1\n```\n\n**Default:**\n```ini\ncwpkota = 0\n```", .status = 0 }, - { .param = "headermode", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA_MERLIN` compilation flag)**\n\nHeader mode for Nagra Merlin readers.\n\n```ini\nheadermode = 0 # header 0x00\nheadermode = 1 # header 0x04 (default)\n```\n\n**Format:**\n```ini\nheadermode = 0|1\n```\n\n**Example:**\n```ini\nheadermode = 0\n```\n\n**Default:**\n```ini\nheadermode = 1\n```", .status = 0 }, - { .param = "cak63nuid", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA` compilation flag)**\n\nNagra CAK6.3 NUID (Network Unique Identifier). 4 bytes in hexadecimal.\n\n**Format:**\n```ini\ncak63nuid = hex_bytes\n```\n\n**Example:**\n```ini\ncak63nuid = 12345678\n```\n\n**Default:**\n```ini\ncak63nuid =\n```", .status = 0 }, - { .param = "cak63cwekey", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_NAGRA` compilation flag)**\n\nNagra CAK6.3 CWPK (Control Word Protection Key). 16 bytes in hexadecimal.\n\n**Format:**\n```ini\ncak63cwekey = hex_bytes\n```\n\n**Example:**\n```ini\ncak63cwekey = 0102030405060708090A0B0C0D0E0F10\n```\n\n**Default:**\n```ini\ncak63cwekey =\n```", .status = 0 }, - { .param = "cak7_mode", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nInitialize card in CAK7 (Merlin) mode for Nagravision readers.\n\n```ini\ncak7_mode = 0 # standard mode (default)\ncak7_mode = 1 # CAK7/Merlin mode\n```\n\n**Format:**\n```ini\ncak7_mode = 0|1\n```\n\n**Example:**\n```ini\ncak7_mode = 1\n```\n\n**Default:**\n```ini\ncak7_mode = 0\n```", .status = 0 }, - { .param = "card_startdate_basemonth", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nBase month for card start date calculation.\n\n**Format:**\n```ini\ncard_startdate_basemonth = month\n```\n\n**Example:**\n```ini\ncard_startdate_basemonth = 1\n```\n\n**Default:**\n```ini\ncard_startdate_basemonth = 1\n```", .status = 0 }, - { .param = "card_startdate_baseyear", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nBase year for card start date calculation.\n\n**Format:**\n```ini\ncard_startdate_baseyear = year\n```\n\n**Example:**\n```ini\ncard_startdate_baseyear = 1997\n```\n\n**Default:**\n```ini\ncard_startdate_baseyear = 1997\n```", .status = 0 }, - { .param = "card_expiredate_basemonth", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nBase month for card expiration date calculation.\n\n**Format:**\n```ini\ncard_expiredate_basemonth = month\n```\n\n**Example:**\n```ini\ncard_expiredate_basemonth = 1\n```\n\n**Default:**\n```ini\ncard_expiredate_basemonth = 1\n```", .status = 0 }, - { .param = "card_expiredate_baseyear", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nBase year for card expiration date calculation.\n\n**Format:**\n```ini\ncard_expiredate_baseyear = year\n```\n\n**Example:**\n```ini\ncard_expiredate_baseyear = 1997\n```\n\n**Default:**\n```ini\ncard_expiredate_baseyear = 1997\n```", .status = 0 }, - { .param = "ins7e", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nAdd 26 hex-bytes payload for **NDS Videoguard 2 SCs**.\n\n```ini\nins7e = payload # 26 hex bytes\n = # None (default)\n```\n\n⚠️ **Attention:** Valid for physical readers only", .status = 0 }, - { .param = "ins42", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nINS42 command data for Irdeto readers.\n\n**Format:**\n```ini\nins42 = hex_bytes\n```\n\n**Example:**\n```ini\nins42 = 0102030405\n```\n\n**Default:**\n```ini\nins42 =\n```", .status = 0 }, - { .param = "ins7e11", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nAdd TA1 Byte for **NDS Videoguard 2 SCs**.\n\n```ini\nins7e11 = # None (default)\n = 11 # 0001 FI + 0001 DI (1 x)\n = 13 # 0001 FI + 0011 DI (4 x)\n = 14 # 0001 FI + 0100 DI (8 x)\n = 15 # 0001 FI + 0101 DI (16 x)\n```\n\n⚠️ **Attention:** Valid for physical readers only", .status = 0 }, - { .param = "ins2e06", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nAdd check control for pin payload (4 hex bytes) for **NDS Videoguard 2 SCs**.\n\n```ini\nins2e06 = Payload # 4 hex bytes\n = # None (blank, default)\n```\n\n⚠️ **Attention:** Valid for physical readers only", .status = 0 }, - { .param = "k1_generic", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nGeneric K1 key for DRE/Bulcrypt readers. DES or 3DES key in hexadecimal.\n\n**Format:**\n```ini\nk1_generic = hex_bytes\n```\n\n**Example:**\n```ini\nk1_generic = 0102030405060708\n```\n\n**Default:**\n```ini\nk1_generic =\n```", .status = 0 }, - { .param = "k1_unique", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nUnique K1 key for DRE/Bulcrypt readers. DES or 3DES key in hexadecimal.\n\n**Format:**\n```ini\nk1_unique = hex_bytes\n```\n\n**Example:**\n```ini\nk1_unique = 0102030405060708\n```\n\n**Default:**\n```ini\nk1_unique =\n```", .status = 0 }, - { .param = "fix07", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nEnable 0x07 fix for **NDS Videoguard 2 SCs**.\n\n```ini\nfix07 = 0 # Disabled\nfix07 = 1 # Enabled (default)\n```\n\n⚠️ **Attention:** Valid for physical readers only\n\n**Format:**\n```ini\nfix07 = 0|1\n```\n\n**Example:**\n```ini\nfix07 = 0\n```\n\n**Default:**\n```ini\nfix07 = 1\n```", .status = 0 }, - { .param = "fix9993", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nEnable fix for 9993 error with CAID 0919 SCs.\n\n```ini\nfix9993 = 0 # Disabled (default)\nfix9993 = 1 # Enabled\n```\n\n**Format:**\n```ini\nfix9993 = 0|1\n```\n\n**Example:**\n```ini\nfix9993 = 1\n```\n\n**Default:**\n```ini\nfix9993 = 0\n```", .status = 0 }, - { .param = "readtiers", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nMethod to get tiers of **NDS Videoguard SCs**.\n\n```ini\nreadtiers = 0 # Disabled (default)\nreadtiers = 1 # ins70 (new) method\nreadtiers = 2 # ins76 (old) method\n```\n\n**Format:**\n```ini\nreadtiers = 0|1|2\n```\n\n**Example:**\n```ini\nreadtiers = 1\n```\n\n**Default:**\n```ini\nreadtiers = 0\n```", .status = 0 }, - { .param = "force_irdeto", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nForce Irdeto SC mode even if RSA key is set for Irdeto tunneled Nagravision SC.\n\n```ini\nforce_irdeto = 0 # No (default)\nforce_irdeto = 1 # Yes\n```\n\n**Format:**\n```ini\nforce_irdeto = 0|1\n```\n\n**Example:**\n```ini\nforce_irdeto = 1\n```\n\n**Default:**\n```ini\nforce_irdeto = 0\n```", .status = 0 }, - { .param = "needsglobalfirst", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_CRYPTOWORKS` compilation flag)**\n\nSend global EMMs before unique EMMs for Cryptoworks readers.\n\n```ini\nneedsglobalfirst = 0 # disabled (default)\nneedsglobalfirst = 1 # send global EMMs first\n```\n\n**Format:**\n```ini\nneedsglobalfirst = 0|1\n```\n\n**Example:**\n```ini\nneedsglobalfirst = 1\n```\n\n**Default:**\n```ini\nneedsglobalfirst = 0\n```", .status = 0 }, - { .param = "ecmnotfoundlimit", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nNumber of ECMs with \"not found\" answer until the reader will be restarted.\n\n```ini\necmnotfoundlimit = count\n = 0 # No limit (default)\n```\n\n**Default:**\n```ini\necmnotfoundlimit = 0\n```", .status = 0 }, - { .param = "ecmwhitelist", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nDefine valid ECM length **in hex** and provid for physical reader.\n\n**Syntax:**\n```ini\necmwhitelist = [CAID[@provid]:]length[,length]...[;[CAID[@provid]:]length[,length]...]...\n```\n\n**Examples:**\n```ini\necmwhitelist = 10,20,30,0a,0b,0c\necmwhitelist = 0100:10,20;0200@12345:0a,4b\n = # None (default) and provid 000000\n```\n\n⚠️ **In normal operation mode this parameter is not required!**\n\n📋 **[List of ECM lengths](http://www.streamboard.tv/oscam/wiki/ECMLengthList)**", .status = 0 }, - { .param = "ecmheaderwhitelist", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nSet valid ECM header per CAID and provid **in hex**.\n\n**Syntax:**\n```ini\necmheaderwhitelist = [CAID[@provid]:]header[,header]...[;[@provid]:]header[,header]...]...\n```\n\n**Default:** None, provid = 000000\n\n📋 **[HeaderWhitelist](http://www.streamboard.tv/oscam/wiki/HeaderWhitelist)**", .status = 0 }, - { .param = "detect", .config = "server", .section = "reader", .text = "**🔵 Parameter depends on setup/program version**\n\nCard status (inserted or removed) is detected via a serial device (UART/SCI) handshake input line.\n\n**Values:**\n```ini\ndetect = cd (default) # Carrier Detect\n = cts # Clear To Send\n = dsr # Data Set Ready\n = ring # Ring Indicator\n = none # No detection line connected, card always detected as inside\n```\n\n- `none` means: no detection line connected to the card reader. The card is always detected as being inside cardreader.\n- Inverse detect signal: prefix \"!\" (e.g., `detect = !cts`)\n\n**If `use_gpio = 1` is set:**\n```ini\ndetect = gpio1...gpio7 # Card status detected via a GPIO\n```\n\nGPIO means \"general purpose input output\".\n\n**Example:**\n```ini\n[reader]\nlabel = mymouse\ndescription = mymouse xxx\nprotocol = mouse\ndevice = /dev/ttyUSB0\nservices = xxx\nboxkey = 1122334455667788\nforce_irdeto = 1\ndetect = cd\nmhz = 1000\ncardmhz = 600\ngroup = 1,2,3\nemmcache = 1,3,2\n```", .status = 0 }, - { .param = "nagra_read", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nRead **Nagravision** records (on NCMED cards only).\n\n```ini\nnagra_read = 0 # Disabled (default)\nnagra_read = 1 # Read all records with expired rights\nnagra_read = 2 # Read records with valid rights only\n```\n\n**Format:**\n```ini\nnagra_read = 0|1|2\n```\n\n**Example:**\n```ini\nnagra_read = 2\n```\n\n**Default:**\n```ini\nnagra_read = 0\n```", .status = 0 }, - { .param = "detect_seca_nagra_tunneled_card", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nDetect Seca cards tunneled through Nagra for hybrid cards.\n\n```ini\ndetect_seca_nagra_tunneled_card = 0 # detection disabled\ndetect_seca_nagra_tunneled_card = 1 # detection enabled (default)\n```\n\n**Format:**\n```ini\ndetect_seca_nagra_tunneled_card = 0|1\n```\n\n**Example:**\n```ini\ndetect_seca_nagra_tunneled_card = 0\n```\n\n**Default:**\n```ini\ndetect_seca_nagra_tunneled_card = 1\n```", .status = 0 }, - { .param = "mhz", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nSet reader frequency in units of 10 kHz. If mhz > cardmhz you are in overclocking mode.\n\n**Example:**\n```ini\ncardmhz = 600 # (6000 KHz = 6 MHz)\nmhz = 1000 # (10000 KHz = 10 MHz)\n```\n\n**Default:** 357\n\nAuto clock speed in **Dreambox mode**: set to -1.\n\n📋 **[List of default and overclocking card frequencies](http://www.streamboard.tv/oscam/wiki/CardsList)**", .status = 0 }, - { .param = "cardmhz", .config = "server", .section = "reader", .text = "**🔵 Parameter depends on setup/program version**\n\nSet standard SC frequency in units of 10 kHz. For Irdeto SC set to 600.\n\n**Examples:**\n```ini\ncardmhz = 600 # Irdeto card\n = 357 # Default (blank)\n```\n\n**INTERNAL READERS**\n\nIf you use `cardmhz > 2000` OSCam will switch to PLL clocking. Internal readers of boxes from Dream Multimedia GmbH can be clocked more precise with it.\n\nThe used cardmhz should reflect the highest frequency of the PLL crystal in the internal cardreader. OSCam will calculate the best PLL divider that comes nearest to the wanted user card speed specified in cardmhz.\n\n**Recommended settings:**\n- Models with PPC-CPU (DM500/DM600/DM7000/DM7020): `cardmhz = 3150`\n- Models with MIPS-CPU (DM500HD/DM800/DM800SE/DM8k/DM7020HD etc.): `cardmhz = 2700`\n- DM7025 (special): `cardmhz = 8300`\n\n⚠️ **If only the parameter cardmhz is set (without mhz = xxx) then OSCam clocks the card automatically with the ATR!**\n\n**Example:**\nYou have a DM800 HD PVR (MIPS), so you should set cardmhz to 2700. If you have a Nagra card that should run on 5 MHz:\n- Normal clocking: `cardmhz = 2700` and `mhz = 500`\n- Overclocking: `cardmhz = 2700` and `mhz = 900` (card will run at 9 MHz)\n\n⚠️ Keep in mind that most internal readers of non-dreamboxes clock the cards automatically and completely ignore any user clockspeed setting. But you should set cardmhz and mhz anyway, as it's still used to calculate the correct timings in OSCam.\n\n📋 **[List of default and overclocking card frequencies](http://www.streamboard.tv/oscam/wiki/CardsList)**", .status = 0 }, - { .param = "mode", .config = "server", .section = "reader", .text = "**🔵 Parameter depends on setup/program version**\n\nSet card init mode for **AzBox** reader.\n\n```ini\nmode = 1 # AzBox-Reader\n = 0 # None (default)\n```\n\n**Default:**\n```ini\nmode = 0\n```", .status = 0 }, - { .param = "ident", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n⚠️ **Attention:** If in `oscam.conf [global]` loadbalancing is enabled among `lb_mode`, then there may be **no entries**!\n\n⚠️ **Note:** This parameter is only used for EMM and not for ECM. You cannot force ECM to be sent to the card using this parameter.\n\nDefine CAID and ident **SC specific** for reader.\n\n**Syntax:**\n```ini\nident = :[,ident]...[;:[,ident]...]...\n```\n\n**Example:**\n```ini\nident = 0100:123456,234567;0200:345678,456789\n = # Blank, no definition (default)\n```", .status = 0 }, - { .param = "chid", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nDefine **Irdeto ChID** for reader.\n\n**Examples:**\n```ini\nchid = 0100:12\nchid = 0100:12;0604:0000BA,000101,00010E,000141\n = # Blank (default)\n```", .status = 0 }, - { .param = "class", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nDefine class **in hex** SC specific for reader.\n\n**Example:**\n```ini\nclass = 01,02,!1b,!2b # 01 and 02 yes, 1b and 2b no\n = # Blank, no definition (default)\n```", .status = 0 }, - { .param = "aeskeys", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nMultiple 16 bytes AES keys for Viaccess SCs (the used postprocessing AES key is specified through the D2 nano of the ECM).\n\n**Syntax:**\n```\nCAID@ident:AES key #0 CAID #0[,AES key #1 CAID #0],...[;CAID #1@ident:AES key #0 CAID #1[,AES key #1 CAID #1],...]...\n```\n\n**Special AES keys:**\n- `00` = do not return any CW, no AES key specified\n- `FF` = return CW received from the SC, no AES key specified\n\n**Examples:**\n```ini\naeskeys = 0500@012345:000102030405060708090a0b0c0d0e0f;0500@543210:0,0,0f0e0d0c0b0a090807060504030201\naeskeys = 0500@012345:key0,key1,key2,key3,key4,key5,...;0500@543210:key0,key1,key2,key3,key4,key5,...\n```\n\nIf keys are unknown, replace them with 0:\n```ini\naeskeys = 0500@012345:key0,key1,0,0,key4,key5,...\n```", .status = 0 }, - { .param = "group", .config = "server", .section = "reader", .text = "**🔴 Required parameter**\n\nReader assignment to group. Each reader must be listed in one or more groups. This will determine which client has access to what reader.\n\nValid values: 1-64\n\n**Syntax:**\n```ini\ngroup = 1...64[,1...64]...\n```\n\n**Examples:**\n```ini\ngroup = 1 # One group\ngroup = 1,4,5 # Multiple groups\n```\n\n⚠️ **Setting required parameter blank is not allowed!**", .status = 0 }, - { .param = "emmcache", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nSet EMM cache of local reader.\n\n⚠️ **Attention:** Without this parameter, no EMMs are shown in the log!\n\n**Format:**\n```ini\nemmcache = ,,,\n```\n\n**Parameters:**\n\n**``:**\n- `0` = Disable usage of emmcache and emmstats (default)\n- `1` = Enable emmcache, emmstats and save to file if OSCam is stopped\n- `2` = Enable emmcache, emmstats but don't save to file if OSCam is stopped\n\n**``:**\n- `n` = Determines how often one and the same EMM is written (only if `` = 1 or 2)\n\n**``:**\n- `0` = EMM logging disabled\n- `1` = Logging EMM errors\n- `2` = Logging written EMMs\n- `4` = Logging skipped EMMs\n- `8` = Logging blocked EMMs\n- `16` = Logging audisabled EMMs\n\nSummarizing these values is possible. 31 shows all kinds of messages.\n\n**``:**\n- `0` = EMM for STB are ignored (default)\n- `1` = EMM for STB are sent to the reader (very specific usage)\n\n**Examples:**\n```ini\nemmcache = 1,3,10,0 # Cache on, write 3x, log written (2) and blocked (8) = 10, don't send stb-emm\nemmcache = 1,2,6,1 # Cache on, write 2x, log written (2) and skipped (4) = 6, send stb-emm\n```\n\n**Note:** **stb-emm** is only handy for specific usage (Viaccess: see commit [#10584](http://www.streamboard.tv/oscam/changeset/10584)). In Viaccess we saw some EMM-G that are for the STB and not for the card. Those EMMs are used, for example, to define overencryption key (AES) into the STB to encrypt STB-Card dialog.", .status = 0 }, - { .param = "blockemm-unknown", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nBlock unknown types of EMMs.\n\n```ini\nblockemm-unknown = 0 # No block (default)\nblockemm-unknown = 1 # Block all unknown kinds of EMMs\n```\n\n**Format:**\n```ini\nblockemm-unknown = 0|1\n```\n\n**Example:**\n```ini\nblockemm-unknown = 1\n```\n\n**Default:**\n```ini\nblockemm-unknown = 0\n```", .status = 0 }, - { .param = "blockemm-u", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nBlock unique EMMs.\n\n```ini\nblockemm-u = 0 # No block (default)\nblockemm-u = 1 # Block EMMs, which are addressed to card immediately\n```\n\n**Format:**\n```ini\nblockemm-u = 0|1\n```\n\n**Example:**\n```ini\nblockemm-u = 1\n```\n\n**Default:**\n```ini\nblockemm-u = 0\n```", .status = 0 }, - { .param = "blockemm-s", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nBlock shared EMMs.\n\n```ini\nblockemm-s = 0 # No block (default)\nblockemm-s = 1 # Block EMMs, which are addressed to certain groups of cards\n```\n\n**Format:**\n```ini\nblockemm-s = 0|1\n```\n\n**Example:**\n```ini\nblockemm-s = 1\n```\n\n**Default:**\n```ini\nblockemm-s = 0\n```", .status = 0 }, - { .param = "blockemm-g", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nBlock global EMMs.\n\n```ini\nblockemm-g = 0 # No block (default)\nblockemm-g = 1 # Block EMMs, which are addressed to all cards\n```\n\n**Format:**\n```ini\nblockemm-g = 0|1\n```\n\n**Example:**\n```ini\nblockemm-g = 1\n```\n\n**Default:**\n```ini\nblockemm-g = 0\n```", .status = 0 }, - { .param = "saveemm-unknown", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nSave unknown EMMs to file. The path can be defined with `emmlogdir=` in `oscam.conf` (default=config-dir).\n\n```ini\nsaveemm-unknown = 0 # Disabled (default)\nsaveemm-unknown = 1 # Enabled\n```\n\n**Format:**\n```ini\nsaveemm-unknown = 0|1\n```\n\n**Example:**\n```ini\nsaveemm-unknown = 1\n```\n\n**Default:**\n```ini\nsaveemm-unknown = 0\n```", .status = 0 }, - { .param = "saveemm-u", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nSave unique EMMs to file. The path can be defined with `emmlogdir=` in `oscam.conf` (default=config-dir).\n\n```ini\nsaveemm-u = 0 # Disabled (default)\nsaveemm-u = 1 # Enabled\n```\n\n**Format:**\n```ini\nsaveemm-u = 0|1\n```\n\n**Example:**\n```ini\nsaveemm-u = 1\n```\n\n**Default:**\n```ini\nsaveemm-u = 0\n```", .status = 0 }, - { .param = "saveemm-s", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nSave shared EMMs to file. The path can be defined with `emmlogdir=` in `oscam.conf` (default=config-dir).\n\n```ini\nsaveemm-s = 0 # Disabled (default)\nsaveemm-s = 1 # Enabled\n```\n\n**Format:**\n```ini\nsaveemm-s = 0|1\n```\n\n**Example:**\n```ini\nsaveemm-s = 1\n```\n\n**Default:**\n```ini\nsaveemm-s = 0\n```", .status = 0 }, - { .param = "saveemm-g", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nSave global EMMs to file. The path can be defined with `emmlogdir=` in `oscam.conf` (default=config-dir).\n\n```ini\nsaveemm-g = 0 # Disabled (default)\nsaveemm-g = 1 # Enabled\n```\n\n**Format:**\n```ini\nsaveemm-g = 0|1\n```\n\n**Example:**\n```ini\nsaveemm-g = 1\n```\n\n**Default:**\n```ini\nsaveemm-g = 0\n```", .status = 0 }, - { .param = "blockemm-bylen", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nBlock all types of EMMs by length. Maximum 10 values.\n\n**Syntax:**\n```ini\nblockemm-bylen = [length range,length range]... (decimal)\n```\n\n**Example:**\n```ini\nblockemm-bylen = 1-10,11-\n```\n\n**Default:**\n```ini\nblockemm-bylen =\n```", .status = 0 }, - { .param = "lb_weight", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nThe higher the value, the higher the probability for reader selection. It's a divider for the average response time.\n\n**Format:**\n```ini\nlb_weight = weight\n```\n\n**Example:**\n```ini\nlb_weight = 200\n```\n\n**Default:**\n```ini\nlb_weight = 100\n```", .status = 0 }, - { .param = "lb_force_fallback", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nSet the reader always as fallback for load balancing without considering the reader's statistics.\n\n```ini\nlb_force_fallback = 0 # Default\nlb_force_fallback = 1 # Set reader always as fallback\n```\n\n**Format:**\n```ini\nlb_force_fallback = 0|1\n```\n\n**Example:**\n```ini\nlb_force_fallback = 1\n```\n\n**Default:**\n```ini\nlb_force_fallback = 0\n```", .status = 0 }, - { .param = "savenano", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nList of EMM-nanos (in hex w/o 0x) to save or all EMM-nanos. Only valid for physical readers. The path can be defined with `emmlogdir=` in `oscam.conf` (default=config-dir).\n\n**Syntax:**\n```ini\nsavenano = nano[,nano]...|all\n```\n\n**Examples:**\n```ini\nsavenano = 45,93,7a,ff\n = all\n = # Blank (default)\n```", .status = 0 }, - { .param = "blocknano", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nList of EMM-nanos to block (in hex w/o 0x) or all EMM-nanos. Only valid for physical readers!\n\n**Examples:**\n```ini\nblocknano = 45,93,7a,ff\n = all\n = # Blank (default)\n```", .status = 0 }, - { .param = "dropbadcws", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nReject bad CWs, send \"not found\" instead of bad CWs.\n\n```ini\ndropbadcws = 0 # Default\ndropbadcws = 1 # Reject bad CWs\n```\n\n**Format:**\n```ini\ndropbadcws = 0|1\n```\n\n**Example:**\n```ini\ndropbadcws = 1\n```\n\n**Default:**\n```ini\ndropbadcws = 0\n```", .status = 0 }, - { .param = "disablecrccws", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nDisable CW checksum test.\n\n```ini\ndisablecrccws = 0 # Enable (default)\ndisablecrccws = 1 # Disable CW checksum test\n```\n\n**Format:**\n```ini\ndisablecrccws = 0|1\n```\n\n**Example:**\n```ini\ndisablecrccws = 1\n```\n\n**Default:**\n```ini\ndisablecrccws = 0\n```", .status = 0 }, - { .param = "use_gpio", .config = "server", .section = "reader", .text = "**🔵 Parameter depends on setup/program version**\n\nUse GPIO as card detect/reset.\n\n```ini\nuse_gpio = 0 # Off (default)\nuse_gpio = 1 # On\n```\n\n**Format:**\n```ini\nuse_gpio = 0|1\n```\n\n**Example:**\n```ini\nuse_gpio = 1\n```\n\n**Default:**\n```ini\nuse_gpio = 0\n```", .status = 0 }, - { .param = "cccversion", .config = "server", .section = "reader", .text = "**🔵 Parameter depends on setup/program version**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\n**Only for CCcam**\n\nDefine CCcam version.\n\n**Syntax:**\n```ini\ncccversion = ,,\n```\n\n**Example:**\n```ini\ncccversion = 1.2.34\n```", .status = 0 }, - { .param = "cccmaxhops", .config = "server", .section = "reader", .text = "**🔵 Parameter depends on setup/program version**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nDefine CCcam maximum SC distance hops.\n\n```ini\ncccmaxhops = 0 # Local SCs only\n = 1 # Local SCs + 1 hop\n = 2 # Local SCs + 2 hops\n = ... # And so on\n = 10 # Default\n```\n\n**Default:**\n```ini\ncccmaxhops = 10\n```", .status = 0 }, - { .param = "cccmindown", .config = "server", .section = "reader", .text = "**🔵 Parameter depends on setup/program version**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nFilters all readers with hops smaller than number.\n\n```ini\ncccmindown = number\n = 0 # Default\n```\n\n**Default:**\n```ini\ncccmindown = 0\n```", .status = 0 }, - { .param = "ccckeepalive", .config = "server", .section = "reader", .text = "**🔵 Parameter depends on setup/program version**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nSend keepalive messages to keep connection to remote CCCam server up.\n\n```ini\nccckeepalive = 0 # No (default)\nccckeepalive = 1 # Yes\n```\n\n**Format:**\n```ini\nccckeepalive = 0|1\n```\n\n**Example:**\n```ini\nccckeepalive = 1\n```\n\n**Default:**\n```ini\nccckeepalive = 0\n```", .status = 0 }, - { .param = "cccam_reshare", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nReshare level of CCC proxy cards to be sent into gbox network.\n\n```ini\ncccam_reshare = -1 # No resharing (default)\n = 0 # Reshare for direct peer only\n = 1 # Reshare for direct peer plus next level\n = x # Resharing for direct peer plus x share level\n```\n\n**Default:**\n```ini\ncccam_reshare = -1\n```", .status = 0 }, - { .param = "cccreconnect", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nReconnect again after ECM request timeout in milliseconds.\n\n```ini\ncccreconnect = timeout # Timeout in milliseconds\n = 12000 # Default\n```\n\n**Default:**\n```ini\ncccreconnect = 12000\n```", .status = 0 }, - { .param = "ccchop", .config = "server", .section = "reader", .text = "**🔵 Parameter depends on setup/program version**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nSet hop for **non** CCCam readers.\n\n```ini\nccchop = hop\n = 0 # Default\n```\n\n**Default:**\n```ini\nccchop = 0\n```", .status = 0 }, - { .param = "use_ssl", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GHTTP` compilation flag)**\n\nUse SSL for ghttp protocol.\n\n```ini\nuse_ssl = 0 # Default\nuse_ssl = 1 # Use SSL for ghttp protocol\n```\n\n**Format:**\n```ini\nuse_ssl = 0|1\n```\n\n**Example:**\n```ini\nuse_ssl = 1\n```\n\n**Default:**\n```ini\nuse_ssl = 0\n```", .status = 0 }, - { .param = "force_ua", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_DRE` compilation flag)**\n\nForce UA (4 bytes or 8 chars expressed in hexa).\n\n**Example:**\n```ini\nforce_ua = 12345678\n```", .status = 0 }, - { .param = "exec_cmd_file", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\n**(requires `READER_DRE` compilation flag)**\n\nPath to a script.\n\n**Example:**\n```ini\nexec_cmd_file = /path/to/script.sh\n```", .status = 0 }, - { .param = "resetalways", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nAlways reset the card before each ECM request.\n\n```ini\nresetalways = 0 # normal operation (default)\nresetalways = 1 # always reset card\n```\n\n**Format:**\n```ini\nresetalways = 0|1\n```\n\n**Example:**\n```ini\nresetalways = 1\n```\n\n**Default:**\n```ini\nresetalways = 0\n```", .status = 0 }, - { .param = "deprecated", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nFirst the SC will be initialized in normal mode. If it fails, the SC will be automatically reverted to deprecated mode, so that the SC speed will not be changed and the communication will remain on normal ATR speed of 9600 baud.\n\n```ini\ndeprecated = 0 # Normal mode (default)\ndeprecated = 1 # Use deprecated SC mode only\n```\n\n**Format:**\n```ini\ndeprecated = 0|1\n```\n\n**Example:**\n```ini\ndeprecated = 1\n```\n\n**Default:**\n```ini\ndeprecated = 0\n```", .status = 0 }, - { .param = "audisabled", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nExclude reader from auto AU (auto update).\n\n```ini\naudisabled = 0 # Not excluded (default)\naudisabled = 1 # Excluded\n```\n\n**Format:**\n```ini\naudisabled = 0|1\n```\n\n**Example:**\n```ini\naudisabled = 1\n```\n\n**Default:**\n```ini\naudisabled = 0\n```", .status = 0 }, - { .param = "auprovid", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nSet provider ID to use the right reader for auto AU.\n\n**Example:**\n```ini\nauprovid = 123456\n```\n\n**Default:**\n```ini\nauprovid =\n```", .status = 0 }, - { .param = "ndsversion", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nSet NDS **Videoguard** version.\n\n```ini\nndsversion = 0 # Autodetection (default)\n = 1 # NDS Videoguard 1\n = 12 # NDS Videoguard 1+\n = 2 # NDS Videoguard 2\n```\n\n**Default:**\n```ini\nndsversion = 0\n```", .status = 0 }, - { .param = "ratelimitecm", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nNumber of different SIDs in ECMs allowed for an interval.\n\n```ini\nratelimitecm = number\n = 0 # Default\n```\n\n**Default:**\n```ini\nratelimitecm = 0\n```", .status = 0 }, - { .param = "ecmunique", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nEnable check for matching ECM hash in ratelimit slot.\n\n```ini\necmunique = 0 # Default\necmunique = 1 # Enable check for matching ECM hash in ratelimit slot\n```\n\n⚠️ **Remark:** Parameter `ratelimitecm` must be set to be able to enable this option!\n\n**Format:**\n```ini\necmunique = 0|1\n```\n\n**Example:**\n```ini\necmunique = 1\n```\n\n**Default:**\n```ini\necmunique = 0\n```", .status = 0 }, - { .param = "ratelimittime", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nInterval for rate limit in milliseconds.\n\n```ini\nratelimittime = milliseconds\n = 0 # Default\n```\n\n**Default:**\n```ini\nratelimittime = 0\n```", .status = 0 }, - { .param = "srvidholdtime", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nTime to keep service ID in ratelimit slot. During this time checking for `ecmunique` is disabled.\n\n```ini\nsrvidholdtime = milliseconds\n = 0 # Default\n```\n\n**Default:**\n```ini\nsrvidholdtime = 0\n```", .status = 0 }, - { .param = "cooldown", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nDefine cooldown.\n\n**Syntax:**\n```ini\ncooldown = delay,duration\n```\n\n**Parameters:**\n- `delay` = Delay in milliseconds for which the reader is allowed to do more ECM requests than defined by parameter `ratelimitecm`\n- `duration` = Duration in milliseconds the reader needs to cooldown\n\nBoth parameters are mandatory when used.\n\n⚠️ **Parameters `ratelimitecm` and `ratelimittime` are required!**\n\n**Default:**\n```ini\ncooldown =\n```", .status = 0 }, - { .param = "cooldowndelay", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nCooldown delay in milliseconds. Time delay during which the reader is allowed to process more ECM requests than defined by ratelimitecm.\n\n**Format:**\n```ini\ncooldowndelay = milliseconds\n```\n\n**Example:**\n```ini\ncooldowndelay = 5000\n```\n\n**Default:**\n```ini\ncooldowndelay =\n```", .status = 0 }, - { .param = "cooldowntime", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nCooldown duration in milliseconds. Time the reader needs to cool down after exceeding rate limits.\n\n**Format:**\n```ini\ncooldowntime = milliseconds\n```\n\n**Example:**\n```ini\ncooldowntime = 60000\n```\n\n**Default:**\n```ini\ncooldowntime =\n```", .status = 0 }, - { .param = "maxparallel", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nMaximum number of parallel active services allowed for this reader.\n\nUseful for limiting load on readers with slot restrictions. When the limit is reached, the reader is temporarily skipped and other readers are tried. A service slot is reserved only when a reader delivers a CW (not when the request is sent). This prevents readers from blocking capacity for services they don't end up serving when multiple readers are queried simultaneously.\n\nA service slot expires when no ECM is received within the measured ECM interval plus the `paralleltimeout` buffer.\n\n```ini\nmaxparallel = 0 # unlimited (default)\nmaxparallel = 1 # only 1 active service at a time\nmaxparallel = 2 # max 2 active services\n```\n\n**Format:**\n```ini\nmaxparallel = count\n```\n\n**Example:**\n```ini\nmaxparallel = 2\n```\n\n**Default:**\n```ini\nmaxparallel = 0\n```\n\n⚠️ **After changing `maxparallel` or `parallelfactor`, OSCam must be restarted.**", .status = 0 }, - { .param = "parallelfactor", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nMultiplier for pending slots used during zapping. Pending slots allow temporary capacity overrun while switching channels, preventing black screens when zapping with a single reader.\n\nWhen zapping, new services go to pending slots if active slots are full. Pending services are promoted to active when slots free up (FIFO), or dropped when active services prove they're still active by sending ECMs (FIFO).\n\nThe number of pending slots is calculated as: `round(maxparallel × parallelfactor)`\n\n```ini\nparallelfactor = 0 # disable pending slots (strict limit, may cause black screen when zapping)\nparallelfactor = 1.5 # default - with maxparallel=2: 3 pending slots\nparallelfactor = 2.0 # with maxparallel=2: 4 pending slots\n```\n\n**Pending slots by configuration:**\n\n| maxparallel | parallelfactor | Pending Slots |\n|-------------|----------------|---------------|\n| 1 | 1.5 | 2 |\n| 2 | 1.5 | 3 |\n| 4 | 1.5 | 6 |\n| 1 | 0 | 0 (disabled) |\n\n**Format:**\n```ini\nparallelfactor = factor\n```\n\n**Example:**\n```ini\nparallelfactor = 1.5\n```\n\n**Default:**\n```ini\nparallelfactor = 1.5\n```\n\n⚠️ **After changing `maxparallel` or `parallelfactor`, OSCam must be restarted.**", .status = 0 }, - { .param = "paralleltimeout", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nTimeout buffer in milliseconds added to the measured ECM interval to determine when a service slot expires.\n\nThe ECM interval is measured automatically per service. A service slot expires when no ECM is received within (measured_interval + paralleltimeout). If no interval has been measured yet, a default timeout of 10000 ms plus paralleltimeout is used.\n\n```ini\nparalleltimeout = 1000 # default\nparalleltimeout = 1500 # 1.5 seconds buffer\n```\n\n**Format:**\n```ini\nparalleltimeout = milliseconds\n```\n\n**Example:**\n```ini\nparalleltimeout = 1500\n```\n\n**Default:**\n```ini\nparalleltimeout = 1000\n```", .status = 0 }, - { .param = "read_old_classes", .config = "server", .section = "reader", .text = "**🟢 Optional parameter**\n\nRead old classes from Viaccess cards.\n\n```ini\nread_old_classes = 0 # read only current classes\nread_old_classes = 1 # read old classes too (default)\n```\n\n**Format:**\n```ini\nread_old_classes = 0|1\n```\n\n**Example:**\n```ini\nread_old_classes = 0\n```\n\n**Default:**\n```ini\nread_old_classes = 1\n```", .status = 0 }, - { .param = "P", .config = "dvbapi", .section = "", .text = "```\nP: [CAID]:[provider ID]:[service ID]:[ECM PID]:[CHID] [continue]\n```\nSets priority for specific CAIDs or providers. The optional `continue` parameter (value: 1) forces continuous retry attempts on the specified CAID, useful for Pay-Per-View services or card activation scenarios.", .status = 0 }, - { .param = "I", .config = "dvbapi", .section = "", .text = "```\nI: [CAID]:[provider ID]:[service ID]:[ECM PID]:[CHID]\n```\nIgnores specific encryption providers or Pay TV providers to prevent unnecessary ECM requests.", .status = 0 }, - { .param = "M", .config = "dvbapi", .section = "", .text = "```\nM: [CAID]:[provider ID]:[service ID]:[ECM PID] [target CAID]:[target provider ID]\n```\nMaps one CAID/provider to another, useful for redirecting requests (e.g., mapping Sky HD channels for S02 or D02 cards).", .status = 0 }, - { .param = "D", .config = "dvbapi", .section = "", .text = "```\nD: [CAID]:[provider ID]:[service ID]:[ECM PID] delay\n```\nAdds a delay in milliseconds before writing the control word, useful when the server responds too quickly.", .status = 0 }, - { .param = "L", .config = "dvbapi", .section = "", .text = "```\nL: [CAID]:[provider ID]:[service ID]:[ECM PID] ECM length (hexa)\n```\nFilters ECM requests to only allow specific ECM lengths (in hexadecimal), useful for filtering broken mappings.", .status = 0 }, - { .param = "X", .config = "dvbapi", .section = "", .text = "```\nX: [CAID]:[provider ID]:[service ID]:[ECM PID] demux\n```\nAdds decoding on an extra demux index on the same CA device (not supported on all set-top boxes).", .status = 0 }, - { .param = "J", .config = "dvbapi", .section = "", .text = "```\nJ: [CAID]:[provider ID]:[service ID]:[ECM PID] join\n```\nJoins a CAID/provider/ECM PID to another ECM PID.", .status = 0 }, - { .param = "A", .config = "dvbapi", .section = "", .text = "```\nA: ::[service ID]:[video PID]:[provider ID]::[ECM PID]\n```\nSets a dummy ECM request with CAID FFFF for services with constant control words (for STBs without PMT PID support only).", .status = 0 }, - { .param = "S", .config = "dvbapi", .section = "", .text = "```\nS: [device] [PMT file name]\n```\nSettings for DVB API device name and PMT file name (only valid for STAPI).", .status = 0 }, - { .param = "Priority", .config = "dvbapi", .section = "", .text = "```\nP: 0100:123456 # Prioritize CAID 0100 with provider 123456\nP: 0100 1 # Prioritize CAID 0100 with continuous retry (for PPV/card activation)\nP: : 1 # Client continues requesting after 3 failed attempts (all CAIDs)\nP: :1234 # Prioritize ECM with provider ID 1234 on all services\nP: 0200 # Prioritize CAID 0200\nP: 0300::9ABC # Prioritize CAID 0300 only on service 9ABC\nP: 1702 # Prioritize Sky S02\nP: 1830 # Prioritize HD+ HD01\nP: 0D95 # Prioritize ORF-ICE\n```", .status = 0 }, - { .param = "Ignore", .config = "dvbapi", .section = "", .text = "```\nI: :654321 # Ignore provider ID 654321 for all services\nI: 0 # Ignore all CAIDs not previously specified in this file\nI: 09C4 # Ignore Sky V13\n```", .status = 0 }, - { .param = "Mapping", .config = "dvbapi", .section = "", .text = "```\nM: 0400 0500:123456 # Map CAID 0400 to CAID 0500 with provider ID 123456\nM: 1834:000000:007E 1722 # Map CAID 1834 with provider 000000 and SID 007E to CAID 1722\n```", .status = 0 }, - { .param = "Delay", .config = "dvbapi", .section = "", .text = "```\nD: 0600 200 # Wait 200 ms before writing CW for CAID 0600\n```", .status = 0 }, - { .param = "ECM", .config = "dvbapi", .section = "", .text = "```\nL: 0700 8e # Only allow ECM length 8e (hex) for this CAID to filter broken mappings\n```", .status = 0 }, - { .param = "Multicrypt", .config = "dvbapi", .section = "", .text = "For channels with multiple encryption systems (e.g., Sky Germany with both Nagravision and NDS), prioritize the CAID matching your available cards to avoid unnecessary requests and speed up channel opening.", .status = 0 }, - { .param = "Pay-Per-View", .config = "dvbapi", .section = "", .text = "Use the `continue` parameter to keep retrying on a specific CAID until the card is activated:\n```\nP: 0100 1\n```", .status = 0 }, - { .param = "Server", .config = "dvbapi", .section = "", .text = "Ignore CAIDs for which you have no cards to prevent unnecessary server requests:\n```\nI: 09C4 # Ignore if you don't have V13 cards\n```", .status = 0 }, - { .param = "Parameters", .config = "srvid2", .section = "", .text = "- **service ID**: Service ID (channel ID) in hexadecimal\n- **CAID**: One or more CAIDs in hexadecimal\n- **@PROVID**: Optional provider ID(s) in hexadecimal\n- **channel_name**: Channel name (optional)\n- **type**: Channel type like TV, Radio, etc. (optional)\n- **description**: Additional description (optional)\n- **provider**: Provider or satellite position (optional)", .status = 0 }, - { .param = "Simple", .config = "srvid2", .section = "", .text = "```\n000a:0001,0002,0003|tv name|tv|my description 1|provider 1\n000a:0004,0005,0006|radio name 2|radio|my description 2|provider 2\n000b:0006|tv name 3||my description 3|provider 3\n000b:0007|tv name 4|||provider 4\n```", .status = 0 }, - { .param = "Service", .config = "srvid2", .section = "", .text = "```\n# Service ID 1111, CAID 0100, all provider IDs\n1111:0100|x|y|z|v\n```", .status = 0 }, - { .param = "Service", .config = "srvid2", .section = "", .text = "```\n# Service ID 1111, CAID 0100, provider ID 123456\n1111:0100@123456|x|y|z|v\n```", .status = 0 }, - { .param = "Service", .config = "srvid2", .section = "", .text = "```\n# Service ID 1111, CAID 0100, all providers\n1111:0100@000000|x|y|z|v\n```", .status = 0 }, - { .param = "Multiple", .config = "srvid2", .section = "", .text = "```\n# Service ID 1111, CAID 0100 with provider 123456 AND CAID 0200 with provider 654321\n1111:0100@123456,0200@654321|x|y|z|v\n```", .status = 0 }, - { .param = "Sky", .config = "srvid2", .section = "", .text = "**Sky SAT:**\n\n```\n007F:098C,098D,09F0|13th Street|TV|Sky Starter Paket|Sky\n0085:098C,098D,09F0|Beate Uhse|TV|Sky Starter Paket|Sky\n0194:098C,098D,09F0|Cartoon Network|TV|Sky Starter Paket|Sky\n```\n\n**Sky Vodafone:**\n\n```\n0074:098E,1838,1850,1854,1868|Sky Cinema Action HD|TV|Sky Cinema Paket|Sky\n006B:098E,1838,1850,1854,1868|Sky Cinema Classics HD|TV|Sky Cinema Paket|Sky\n008B:098E,1838,1850,1854,1868|Sky Cinema Family HD|TV|Sky Cinema Paket|Sky\n```", .status = 0 }, - { .param = "HD", .config = "srvid2", .section = "", .text = "```\nEF10:1830,1843,1860,186A,186D,09C4,098C,098D|RTL HD|TV||Astra HD+\nEF11:1830,1843,1860,186A,186D,09C4,098C,098D|VOX HD|TV||Astra HD+\nEF74:1830,1843,1860,186A,186D,09C4,098C,098D|SAT.1 HD|TV||Astra HD+\n```", .status = 0 }, - { .param = "ORF", .config = "srvid2", .section = "", .text = "```\n132F:0D95,0D98,0648,0650,09C4,098C|ORF1 HD|||ORF Digital\n1330:0D95,0D98,0648,0650,09C4,098C|ORF2 HD|||ORF Digital\n33AC:0D95,0D98,0648,0650,09C4,098C|ATV HD|||ORF Digital\n```", .status = 0 }, - { .param = "Multicrypt", .config = "srvid2", .section = "", .text = "For multicrypt channels, list all CAIDs including the management CAID 0000:\n\n```\n0025:0000,1702,1837,1833,09C4,098C,0D05,0D95,0648,0D98,0650|AXN Action|TV||austriasat 19.2°E\n```\n\nThis prevents \"unknown program\" messages in the web interface and shows all CAIDs used by the channel.", .status = 0 }, - { .param = "Finding", .config = "srvid2", .section = "", .text = "Switch to the channel and check the OSCam logs:\n\n```\n2013/10/12 17:45:22 4DB510 c [DVBAPI] Receiver sends PMT command 3 for channel 0025\n2013/10/12 17:45:22 4DB510 c [ADD PID 0] CAID: 1702 ECM_PID: 1725 PROVID: 000000\n2013/10/12 17:45:22 4DB510 c [ADD PID 1] CAID: 1837 ECM_PID: 1FD1 PROVID: 000000\n2013/10/12 17:45:22 4DB510 c [ADD PID 2] CAID: 1833 ECM_PID: 1825 PROVID: 000000\n```\n\nCreate the entry:\n```\n0025:0000,1702,1837,1833,09C4,098C,0D05,0D95,0648,0D98,0650|AXN Action|TV||austriasat 19.2°E\n```", .status = 0 }, - { .param = "Free-to-Air", .config = "srvid2", .section = "", .text = "For FTA channels, use CAID FFFE and provider ID FFFFFE:\n\n```\n2404:FFFE@FFFFFE|Film4|TV||Freesat 28.2°E\n```\n\nNote: FTA CAID changed from 0000 to FFFE, and provider ID changed from 000000 to FFFFFE. Management CAID 0000 is reserved for multicrypt channels.", .status = 0 }, - { .param = "oscam", .config = "srvid2", .section = "", .text = "```\n098C,098D,09F0:007F|Sky|13th Street|TV|Sky Starter Paket\n```", .status = 0 }, - { .param = "oscam", .config = "srvid2", .section = "", .text = "```\n007F:098C,098D,09F0|13th Street|TV|Sky Starter Paket|Sky\n```\n\nThe srvid2 format:\n- Places service ID first (easier to sort by channel)\n- Swaps the position of provider and name fields\n- Otherwise functions identically to oscam.srvid", .status = 0 }, - { .param = "Finding", .config = "srvid2", .section = "", .text = "1. Check OSCam logs for service ID information\n2. Use DVB analysis tools to scan channels\n3. Monitor ECM requests in OSCam logs\n4. Check the web interface status page\n5. Consult online channel databases", .status = 0 }, - { .param = "Extracting", .config = "srvid2", .section = "", .text = "Look for lines like:\n```\n[DVBAPI] Receiver wants to demux srvid 0025 on adapter 0000\n```\n\nThe service ID is 0025 in this example.", .status = 0 }, - { .param = "Organization", .config = "srvid2", .section = "", .text = "- Sort entries by service ID for easy lookup\n- Group related channels together\n- Use comments to separate sections\n- Document special entries", .status = 0 }, - { .param = "Naming", .config = "srvid2", .section = "", .text = "- Use clear, descriptive channel names\n- Include satellite position in provider field\n- Specify channel type (TV, Radio, etc.)\n- Add useful descriptions", .status = 0 }, - { .param = "Maintenance", .config = "srvid2", .section = "", .text = "- Update when channel lineups change\n- Remove obsolete channels\n- Add new channels as they appear\n- Keep synchronized with actual channel availability", .status = 0 }, - { .param = "Example", .config = "srvid2", .section = "", .text = "```\n# Sky Germany SAT - 19.2E (Service IDs 007F-0194)\n007F:098C,098D,09F0|13th Street|TV|Sky Starter Paket|Sky\n0085:098C,098D,09F0|Beate Uhse|TV|Sky Starter Paket|Sky\n\n# Sky Germany Vodafone - Cable (Service IDs 0074-008B)\n0074:098E,1838,1850,1854,1868|Sky Cinema Action HD|TV|Sky Cinema Paket|Sky\n006B:098E,1838,1850,1854,1868|Sky Cinema Classics HD|TV|Sky Cinema Paket|Sky\n\n# HD+ - 19.2E (Service IDs EF10-EF74)\nEF10:1830,1843,1860,186A,186D,09C4,098C,098D|RTL HD|TV||Astra HD+\nEF11:1830,1843,1860,186A,186D,09C4,098C,098D|VOX HD|TV||Astra HD+\n\n# ORF Digital - 19.2E (Service IDs 132F-33AC)\n132F:0D95,0D98,0648,0650,09C4,098C|ORF1 HD|||ORF Digital\n1330:0D95,0D98,0648,0650,09C4,098C|ORF2 HD|||ORF Digital\n```", .status = 0 }, - { .param = "Channel", .config = "srvid2", .section = "", .text = "- Verify file is named oscam.srvid2\n- Check file is in correct configuration directory\n- Ensure Unix line endings (not Windows CRLF)\n- Verify CAID:ProvID:SrvID matches exactly\n- Restart OSCam after changes", .status = 0 }, - { .param = "Wrong", .config = "srvid2", .section = "", .text = "- Check for duplicate entries\n- Verify provider ID priority rules\n- Ensure hexadecimal values are correct\n- Check for typos in CAID/ProvID/SrvID", .status = 0 }, - { .param = "Memory", .config = "srvid2", .section = "", .text = "- Reduce file size by removing unused entries\n- Keep descriptions short\n- Remove unnecessary fields\n- Consider external service ID management", .status = 0 }, - { .param = "Parameters", .config = "provid", .section = "", .text = "- **caid**: Conditional Access Identification in hexadecimal (e.g., 0100, 0500, 1702)\n- **provid**: Provider ID in hexadecimal (e.g., 000000, 003411, 000401)\n- **provider**: Human-readable provider name (e.g., \"Sky Germany\", \"Canal+\")\n- **satellite**: Satellite position or transmission method (e.g., \"19.2E\", \"Astra\", \"Cable\")\n- **language**: Language code or description (e.g., \"de\", \"en\", \"fr\")", .status = 0 }, - { .param = "Basic", .config = "provid", .section = "", .text = "```\n0100:012345|MyPay-TV|Astra 19E|German\n```\n\nThis maps CAID 0100 with Provider ID 012345 to \"MyPay-TV\" on Astra 19.2E in German.", .status = 0 }, - { .param = "Real-World", .config = "provid", .section = "", .text = "```\n# Sky Germany\n1702:000000|Sky Germany S02|19.2E|de\n1833:000401|Sky Germany HD+|19.2E|de\n\n# Canal+\n0100:003311|Canal+ France|19.2E|fr\n0100:003315|Canal+ Espana|19.2E|es\n\n# HD+\n1830:003411|HDplus HD01|19.2E|de\n\n# ORF\n0D05:000000|ORF|19.2E|de\n0D05:000004|ORF ICE|19.2E|de\n\n# Mediaset\n0100:00000B|Mediaset Italy|13E|it\n```", .status = 0 }, - { .param = "With", .config = "provid", .section = "", .text = "```\n# oscam.provid\n# Provider table for OSCam\n# Format: :|||\n\n# German Providers\n1702:000000|Sky Germany S02|19.2E|de\n1830:003411|HDplus HD01|19.2E|de\n\n# French Providers\n0100:003311|Canal+ France|19.2E|fr\n0500:032830|Fransat|5W|fr\n```", .status = 0 }, - { .param = "Sky", .config = "provid", .section = "", .text = "```\n1702:000000|Sky Germany S02|19.2E|de\n1833:000401|Sky Germany NDS|19.2E|de\n09C4:000000|Sky Germany V13|19.2E|de\n```", .status = 0 }, - { .param = "HD", .config = "provid", .section = "", .text = "```\n1830:003411|HDplus HD01|19.2E|de\n1843:003411|HDplus HD02|19.2E|de\n```", .status = 0 }, - { .param = "Canal", .config = "provid", .section = "", .text = "```\n0100:003311|Canal+ France|19.2E|fr\n0100:003315|Canal+ Espana|19.2E|es\n0100:003317|Canal+ Polska|13E|pl\n```", .status = 0 }, - { .param = "ORF", .config = "provid", .section = "", .text = "```\n0D05:000000|ORF|19.2E|de\n0D05:000004|ORF ICE|19.2E|de\n0D95:000000|ORF|19.2E|de\n0D95:000004|ORF ICE|19.2E|de\n```", .status = 0 }, - { .param = "Viaccess", .config = "provid", .section = "", .text = "```\n0500:032830|Fransat|5W|fr\n0500:042400|SRG Swiss|13E|de/fr/it\n0500:050F00|Bis TV|19.2E|fr\n```", .status = 0 }, - { .param = "Finding", .config = "provid", .section = "", .text = "1. Check OSCam logs for CAID:ProvID values\n2. Look at reader statistics in the web interface\n3. Consult online provider databases\n4. Use card information tools", .status = 0 }, - { .param = "Adding", .config = "provid", .section = "", .text = "1. Identify the CAID:ProvID from logs or web interface\n2. Research the provider name and details\n3. Add a new line with the appropriate format\n4. Restart OSCam or reload configuration\n5. Verify the display in web interface", .status = 0 }, - { .param = "Organization", .config = "provid", .section = "", .text = "- Group providers by country or encryption system\n- Use comments to separate sections\n- Keep entries alphabetically sorted within sections\n- Include satellite position for clarity", .status = 0 }, - { .param = "Naming", .config = "provid", .section = "", .text = "- Use clear, descriptive provider names\n- Include card generation if applicable (S02, HD01, etc.)\n- Specify satellite position in standard format (19.2E, 13E, etc.)\n- Use standard language codes (de, en, fr, es, it, etc.)", .status = 0 }, - { .param = "Maintenance", .config = "provid", .section = "", .text = "- Update entries when providers change\n- Remove obsolete providers marked as \"(Old)\"\n- Add new providers as they become available\n- Keep the file synchronized across your OSCam instances", .status = 0 }, - { .param = "Parameters", .config = "ird", .section = "", .text = "- **byte3**: The value of byte 3 in the ECM signature (hexadecimal)\n- **byte4-7**: The values of bytes 4 through 7 in the ECM signature (hexadecimal)\n- **CAID**: The Conditional Access Identification number (hexadecimal)\n- **SID**: The Service ID (hexadecimal)", .status = 0 }, - { .param = "Irdeto", .config = "ird", .section = "", .text = "The primary use case is with Irdeto conditional access systems:\n- Irdeto 1 (CAID 0x0600)\n- Irdeto 2 (CAID 0x0602, 0x0604, 0x0606, 0x0608, etc.)\n- Various Irdeto providers with different signature patterns", .status = 0 }, - { .param = "Automatic", .config = "ird", .section = "", .text = "When working with Irdeto cards or emulators where CAID needs to be determined from ECM signatures rather than being explicitly provided.", .status = 0 }, - { .param = "Empty", .config = "ird", .section = "", .text = "Even if you don't need signature mapping, create an empty file to suppress warnings:\n\n```bash\ntouch oscam.ird\n```", .status = 0 }, - { .param = "Signature", .config = "ird", .section = "", .text = "To populate this file, you typically need to:\n1. Analyze ECM messages from your Irdeto provider\n2. Extract the signature bytes from positions 3-7\n3. Determine the correct CAID and SID for each signature\n4. Add entries to the file", .status = 0 }, - { .param = "Testing", .config = "ird", .section = "", .text = "After adding entries:\n1. Restart OSCam\n2. Monitor logs for CAID detection\n3. Verify that channels open correctly\n4. Adjust mappings if needed", .status = 0 }, - { .param = "Parameters", .config = "srvid", .section = "", .text = "- **CAID**: One or more CAIDs in hexadecimal (max 10 per line)\n- **@PROVID**: Optional provider ID(s) in hexadecimal\n- **service ID**: Service ID (channel ID) in hexadecimal\n- **provider**: Provider or satellite position (optional)\n- **name**: Channel name (optional)\n- **type**: Channel type like TV, Radio, etc. (optional)\n- **description**: Additional description (optional)", .status = 0 }, - { .param = "Simple", .config = "srvid", .section = "", .text = "```\n0001,0002,0003:000a|my provider 1|tv name|tv|my tv package\n0004,0005,0006:000a|my provider 2|radio name 2|radio|my radio package\n0006:000b|my provider 3|tv name 3|\n```", .status = 0 }, - { .param = "CAID", .config = "srvid", .section = "", .text = "```\n# CAID 0100, all provider IDs, service ID 1111\n0100:1111:x|y|z|v\n```", .status = 0 }, - { .param = "CAID", .config = "srvid", .section = "", .text = "```\n# CAID 0100, provider ID 123456, service ID 1111\n0100@123456:1111:x|y|z|v\n```", .status = 0 }, - { .param = "CAID", .config = "srvid", .section = "", .text = "```\n# CAID 0100, all providers, service ID 1111\n0100@000000:1111:x|y|z|v\n```", .status = 0 }, - { .param = "Multiple", .config = "srvid", .section = "", .text = "```\n# CAID 0100 with provider 123456 AND CAID 0200 with provider 654321, both for service ID 1111\n0100@123456,0200@654321:1111:x|y|z|v\n```", .status = 0 }, - { .param = "Sky", .config = "srvid", .section = "", .text = "**Sky SAT:**\n\n```\n098C,098D,09F0:007F|Sky|13th Street|TV|Sky Starter Paket\n098C,098D,09F0:0085|Sky|Beate Uhse|TV|Sky Starter Paket\n098C,098D,09F0:0194|Sky|Cartoon Network|TV|Sky Starter Paket\n```\n\n**Sky Vodafone:**\n\n```\n098E,1838,1850,1854,1868:0074|Sky|Sky Cinema Action HD|TV|Sky Cinema Paket\n098E,1838,1850,1854,1868:006B|Sky|Sky Cinema Classics HD|TV|Sky Cinema Paket\n098E,1838,1850,1854,1868:008B|Sky|Sky Cinema Family HD|TV|Sky Cinema Paket\n```", .status = 0 }, - { .param = "HD", .config = "srvid", .section = "", .text = "```\n1830,1843,1860,186A,186D,09C4,098C,098D:EF10|Astra HD+|RTL HD|TV|\n1830,1843,1860,186A,186D,09C4,098C,098D:EF11|Astra HD+|VOX HD|TV|\n1830,1843,1860,186A,186D,09C4,098C,098D:EF74|Astra HD+|SAT.1 HD|TV|\n```", .status = 0 }, - { .param = "ORF", .config = "srvid", .section = "", .text = "```\n0D95,0D98,0648,0650,09C4,098C:132F|ORF Digital|ORF1 HD\n0D95,0D98,0648,0650,09C4,098C:1330|ORF Digital|ORF2 HD\n0D95,0D98,0648,0650,09C4,098C:33AC|ORF Digital|ATV HD\n```", .status = 0 }, - { .param = "Multicrypt", .config = "srvid", .section = "", .text = "For multicrypt channels, you can list all CAIDs used by the channel, including the management CAID 0000:\n\n```\n0000,1702,1837,1833,09C4,098C,0D05,0D95,0648,0D98,0650:0025|austriasat 19.2°E|AXN Action|TV|\n```\n\nThis prevents \"unknown program\" messages in the web interface and makes it easy to see all CAIDs used by a channel.", .status = 0 }, - { .param = "Finding", .config = "srvid", .section = "", .text = "Switch to the channel and check the OSCam logs:\n\n```\n2013/10/12 17:45:22 4DB510 c [DVBAPI] Receiver sends PMT command 3 for channel 0025\n2013/10/12 17:45:22 4DB510 c [ADD PID 0] CAID: 1702 ECM_PID: 1725 PROVID: 000000\n2013/10/12 17:45:22 4DB510 c [ADD PID 1] CAID: 1837 ECM_PID: 1FD1 PROVID: 000000\n2013/10/12 17:45:22 4DB510 c [ADD PID 2] CAID: 1833 ECM_PID: 1825 PROVID: 000000\n```\n\nUse these CAIDs in your oscam.srvid entry.", .status = 0 }, - { .param = "Free-to-Air", .config = "srvid", .section = "", .text = "For FTA channels, use CAID FFFE:\n\n```\nFFFE:2404|Freesat 28.2°E|Film4|TV|Movies|\n```\n\nNote: FTA CAID changed from 0000 to FFFE. Management CAID 0000 is reserved for multicrypt channels.", .status = 0 }, - { .param = "Finding", .config = "srvid", .section = "", .text = "1. Check OSCam logs for service ID information\n2. Use DVB analysis tools to scan channels\n3. Monitor ECM requests in OSCam logs\n4. Check the web interface status page\n5. Consult online channel databases", .status = 0 }, - { .param = "Extracting", .config = "srvid", .section = "", .text = "Look for lines like:\n```\n[DVBAPI] Receiver wants to demux srvid 0025 on adapter 0000\n```\n\nThe service ID is 0025 in this example.", .status = 0 }, - { .param = "Organization", .config = "srvid", .section = "", .text = "- Group channels by provider or satellite\n- Use comments to separate sections\n- Keep entries sorted by CAID and service ID\n- Document special entries", .status = 0 }, - { .param = "Naming", .config = "srvid", .section = "", .text = "- Use clear, descriptive channel names\n- Include satellite position in provider field\n- Specify channel type (TV, Radio, etc.)\n- Add useful descriptions", .status = 0 }, - { .param = "Maintenance", .config = "srvid", .section = "", .text = "- Update when channel lineups change\n- Remove obsolete channels\n- Add new channels as they appear\n- Keep synchronized with actual channel availability", .status = 0 }, - { .param = "Example", .config = "srvid", .section = "", .text = "```\n# Sky Germany SAT - 19.2E\n098C,098D,09F0:007F|Sky|13th Street|TV|Sky Starter Paket\n098C,098D,09F0:0085|Sky|Beate Uhse|TV|Sky Starter Paket\n\n# Sky Germany Vodafone - Cable\n098E,1838,1850,1854,1868:0074|Sky|Sky Cinema Action HD|TV|Sky Cinema Paket\n098E,1838,1850,1854,1868:006B|Sky|Sky Cinema Classics HD|TV|Sky Cinema Paket\n\n# HD+ - 19.2E\n1830,1843,1860,186A,186D,09C4,098C,098D:EF10|Astra HD+|RTL HD|TV|\n1830,1843,1860,186A,186D,09C4,098C,098D:EF11|Astra HD+|VOX HD|TV|\n\n# ORF Digital - 19.2E\n0D95,0D98,0648,0650,09C4,098C:132F|ORF Digital|ORF1 HD\n0D95,0D98,0648,0650,09C4,098C:1330|ORF Digital|ORF2 HD\n```", .status = 0 }, - { .param = "Channel", .config = "srvid", .section = "", .text = "- Verify file is named oscam.srvid\n- Check file is in correct configuration directory\n- Ensure Unix line endings (not Windows CRLF)\n- Verify CAID:ProvID:SrvID matches exactly\n- Restart OSCam after changes", .status = 0 }, - { .param = "Wrong", .config = "srvid", .section = "", .text = "- Check for duplicate entries\n- Verify provider ID priority rules\n- Ensure hexadecimal values are correct\n- Check for typos in CAID/ProvID/SrvID", .status = 0 }, - { .param = "Memory", .config = "srvid", .section = "", .text = "- Reduce file size by removing unused entries\n- Keep descriptions short\n- Remove unnecessary fields\n- Consider external service ID management", .status = 0 }, - { .param = "Syntax", .config = "tiers", .section = "", .text = "```\nCAID[,CAID]...:TIER_ID|description\n```", .status = 0 }, - { .param = "Format", .config = "tiers", .section = "", .text = "- **CAID**: Conditional Access ID (4-digit hexadecimal), multiple CAIDs can be specified separated by commas\n- **TIER_ID**: Tier/Channel ID (4-digit hexadecimal)\n- **description**: Human-readable description of the tier/service package\n- **:** Separator between CAID list and TIER_ID\n- **|** Separator between TIER_ID and description", .status = 0 }, - { .param = "Important", .config = "tiers", .section = "", .text = "- Use Unix text file format only (LF line endings, not CRLF)\n- Comments start with `#`\n- Multiple CAIDs can share the same TIER_ID\n- Entries should be sorted by TIER_ID within each card/provider section", .status = 0 }, - { .param = "Basic", .config = "tiers", .section = "", .text = "```\n0001,0002,0003:000a|my TIER 1\n0004:000b|my TIER 2\n0005:000b|my TIER 3\n```", .status = 0 }, - { .param = "Sky", .config = "tiers", .section = "", .text = "```\n09C4,09C7:0046|HDplus [NDS]\n09C4,09C7:007D|Sky Sport [NDS]\n09C4,09C7:0081|Sky Bundesliga [NDS]\n09C4,09C7:008E|Beate Uhse [NDS]\n09C4,09C7:00C7|Sky Welt [NDS]\n09C4,09C7:00C8|Sky Film [NDS]\n09C4,09C7:00C9|Sky Welt HD [NDS]\n09C4,09C7:00CA|Sky Film HD [NDS]\n09C4,09C7:00CB|Sky Sport HD [NDS]\n```", .status = 0 }, - { .param = "Sky", .config = "tiers", .section = "", .text = "```\n1702,1833,1722,1834:000F|Sky Sport Portal\n1702,1833,1722,1834:00F0|Sky Bundesliga\n1702,1833,1722,1834:026C|Sky Welt Extra 1\n1702,1833,1722,1834:05E7|Blue Movie Portal\n1702,1833,1722,1834:05F1|Sky Welt HD\n1702,1833,1722,1834:0614|Sky Sport News [SD/HD]\n1702,1833,1722,1834:7D21|Sky Welt\n1702,1833,1722,1834:7D22|Sky Film\n1702,1833,1722,1834:7D23|Sky Sport\n```", .status = 0 }, - { .param = "HD", .config = "tiers", .section = "", .text = "```\n# HDplus HD01 [Nagra]\n1830:0064|Gratis Jahr\n1830:0065|Ungenutzt\n1830:0BEA|HDplus Paket\n\n# HDplus HD02 [Nagra]\n1843:0066|HDplus Paket [Nagra HD02]\n1843:0067|HDplus Paket [Nagra HD02]\n1843:0BEA|HDplus Paket [Nagra HD02]\n```", .status = 0 }, - { .param = "ORF-ICE", .config = "tiers", .section = "", .text = "```\n# Provider 1\n0648:0001|ORF\n0648:0002|ATV / Private\n0648:000D|ORF-ICE Irdeto-Mode Unknown\n0648:F000|ORF-ICE Irdeto-Mode Unknown\n\n# Provider 2\n0648:0015|ORF-ICE Irdeto-Mode Unknown\n```", .status = 0 }, - { .param = "ORF", .config = "tiers", .section = "", .text = "```\n0D05,0D95:0001|ORF All\n0D05,0D95:0010|ATV\n```", .status = 0 }, - { .param = "Understanding", .config = "tiers", .section = "", .text = "TIERs (or CHIDs) are identifiers used by conditional access systems to define which services or channels a subscriber has access to. Each smartcard contains entitlements that specify which TIERs are active.", .status = 0 }, - { .param = "TIER", .config = "tiers", .section = "", .text = "To determine the TIERs available on an NDS card:\n\n1. Set OSCam debug level to 4\n2. Check bytes 11 and 12 in the line below \"Decrypted (Payload)\" in the log\n3. Use this command to extract TIER IDs:\n\n```bash\ngrep -ia -A1 'Decrypted' /tmp/oscam.log | tail -n 1 | sed 's/ */ /g' | cut -d \" \" -f16,17 | sed 's/ //g'\n```", .status = 0 }, - { .param = "WebIF", .config = "tiers", .section = "", .text = "Starting with OSCam 1.20-unstable r5920:\n- If no TIER/CHID assignments are found in `oscam.tiers`\n- OSCam will display CAID/Provider assignments from `oscam.provid` in the WebIF (if available)\n- This provides fallback information when tier definitions are not configured", .status = 0 }, - { .param = "Organizing", .config = "tiers", .section = "", .text = "1. **Group by Provider**: Keep all entries for the same provider together\n2. **Add Comments**: Use comments to identify provider and card type\n3. **Sort by TIER_ID**: Within each provider section, sort entries by TIER_ID (ascending)\n4. **Include Date**: Add a date comment when updating the file", .status = 0 }, - { .param = "Example", .config = "tiers", .section = "", .text = "```\n# oscam.tiers\n# Last updated: 2024-01-15\n# Source: http://www.streamboard.tv/wiki/Tiers\n\n# ============================================\n# Sky Germany V13/G02/G09 [NDS]\n# ============================================\n09C4,09C7:0046|HDplus [NDS]\n09C4,09C7:007D|Sky Sport [NDS]\n# ... more entries ...\n\n# ============================================\n# HD+ [Nagra]\n# ============================================\n1830,1843:0064|HD+ Gratisjahr (HD01)\n1830,1843:0BEA|Jahresabo HD+\n# ... more entries ...\n```", .status = 0 }, - { .param = "Maintaining", .config = "tiers", .section = "", .text = "- TIERs can change when providers update their systems\n- Keep your `oscam.tiers` file updated with current information\n- Community resources like the Streamboard Wiki maintain updated TIER lists\n- Test your configuration after updates to ensure correct display in WebIF", .status = 0 }, - { .param = "Supported", .config = "tiers", .section = "", .text = "The `oscam.tiers` file commonly includes definitions for:\n\n- **Sky Germany**: NDS (09C4, 09C7) and Nagra (1702, 1833, 1722, 1834) systems\n- **HD+**: Nagra systems (1830, 1843)\n- **ORF**: Irdeto (0648, 0650) and CryptoWorks (0D05, 0D95) systems\n- **Unity Media**: Nagra systems (1722, 1831, 1835, 1838)\n- **MTV Unlimited**: Conax systems (0B00)", .status = 0 }, - { .param = "CAID", .config = "tiers", .section = "", .text = "Common CAIDs used in tier definitions:\n\n- **09C4, 09C7, 098C**: NDS (VideoGuard) - Sky Germany\n- **1702, 1722, 1833, 1834**: Nagra - Sky Germany\n- **1830, 1843**: Nagra - HD+\n- **0648, 0650**: Irdeto - ORF\n- **0D05, 0D95, 0D98**: CryptoWorks - ORF\n- **0B00**: Conax - MTV Unlimited", .status = 0 }, - { .param = "TIERs", .config = "tiers", .section = "", .text = "1. **Check File Format**: Ensure Unix line endings (LF, not CRLF)\n2. **Verify Syntax**: Check for correct format with colons and pipes\n3. **Match CAIDs**: Ensure CAIDs in the file match your card's CAID\n4. **Check Permissions**: Verify OSCam can read the file\n5. **Restart OSCam**: Changes require OSCam restart to take effect", .status = 0 }, - { .param = "Finding", .config = "tiers", .section = "", .text = "If you need to identify unknown TIER IDs:\n\n1. Enable debug logging in OSCam (set debug level to 4)\n2. Monitor the log file during card initialization\n3. Look for \"Decrypted (Payload)\" entries\n4. Extract bytes 11-12 for the TIER ID\n5. Add the new TIER to your configuration file", .status = 0 }, - { .param = "Incorrect", .config = "tiers", .section = "", .text = "- Verify TIER_ID matches the actual service\n- Check for typos in hexadecimal values\n- Consult community resources for accurate descriptions\n- Update from maintained TIER lists", .status = 0 }, - { .param = "Parameters", .config = "cert", .section = "", .text = "- **CAID**: Conditional Access Identification - numeric identifier for the encryption provider (in hexadecimal)\n- **reserved**: Reserved field (typically set to 00000000)\n- **IPK**: Issuer Public Key or session key in hexadecimal format", .status = 0 }, - { .param = "Cryptoworks", .config = "cert", .section = "", .text = "This file is specifically designed for Cryptoworks conditional access systems where:\n- Issuer Public Keys are required for decryption\n- Session keys need to be mapped to specific CAIDs\n- Multiple providers may use different keys", .status = 0 }, - { .param = "Key", .config = "cert", .section = "", .text = "The file provides a centralized location for:\n- Storing cryptographic keys\n- Managing multiple CAID mappings\n- Updating keys without modifying other configuration files", .status = 0 }, - { .param = "Parameters", .config = "guess", .section = "", .text = "- **length of ECM**: The length of the ECM message in hexadecimal format\n- **CAID**: The Conditional Access Identification number in hexadecimal format", .status = 0 }, - { .param = "BOMBA", .config = "guess", .section = "", .text = "The primary use case is with the BOMBA protocol, which does not transmit CAID information:\n\n```\n# BOMBA protocol CAID guessing\n10:0B00\n12:0D00\n14:0E00\n```", .status = 0 }, - { .param = "Legacy", .config = "guess", .section = "", .text = "Some older or proprietary protocols may also benefit from CAID guessing:\n- Custom card sharing protocols\n- Modified or stripped-down protocols\n- Legacy conditional access systems", .status = 0 }, - { .param = "m", .config = "whitelist", .section = "", .text = "```\nm: 3456:123456::::: 4567:234567:\n```\n\nUsed for mapping between different identifiers.", .status = 0 }, - { .param = "w", .config = "whitelist", .section = "", .text = "```\nw: [CAID][:][provider ID][:][service ID][:][ECM PID][:][CHID][:][ECM length 1[,ECM length 2]...]]\n```\n\nDefines ECM length whitelisting rules. Only ECMs matching these criteria will be processed.", .status = 0 }, - { .param = "l", .config = "whitelist", .section = "", .text = "```\nl: [CAID][:][provider ID][:][service ID][:][ECM PID][:][CHID][:][ECM length 1[,ECM length 2]...]]\n```\n\nECM length whitelisting that does not proceed with any other ECM length. This is an abbreviation for normal ECM length whitelisting using the `w:` parameter.", .status = 0 }, - { .param = "i", .config = "whitelist", .section = "", .text = "```\ni: [CAID][:][provider ID][:][service ID][:][ECM PID][:][CHID][:][ECM length 1[,ECM length 2]...]]\n```\n\nIgnores ECM requests matching the specified criteria.", .status = 0 }, - { .param = "Field", .config = "whitelist", .section = "", .text = "```\n[prefix]:[CAID][:][provider ID][:][service ID][:][ECM PID][:][CHID][:][ECM length 1[,ECM length 2]...]]\n```", .status = 0 }, - { .param = "Field", .config = "whitelist", .section = "", .text = "- **prefix**: Entry type (`m`, `w`, `l`, or `i`)\n- **CAID**: Conditional Access ID (4-digit hexadecimal)\n- **provider ID**: Provider identifier (hexadecimal)\n- **service ID**: Service identifier (hexadecimal)\n- **ECM PID**: ECM Process ID (hexadecimal)\n- **CHID**: Channel ID (hexadecimal)\n- **ECM length**: ECM length in bytes (decimal), multiple values separated by commas\n\nAll fields after the prefix are optional. Empty fields are indicated by consecutive colons.", .status = 0 }, - { .param = "Basic", .config = "whitelist", .section = "", .text = "```\n# Whitelist all CAID 0100\nw:0100\n\n# Ignore CAID 0200 with service ID 1234\ni:0200::1234\n\n# Ignore CHID 2345\ni:::::2345\n\n# Allow all others (blacklist mode)\nw:\n```", .status = 0 }, - { .param = "Provider-Specific", .config = "whitelist", .section = "", .text = "#### Sky Germany S02 (Nagra)\n\n```\n# S02\nw:1702:000000::::93\n```\n\n#### Sky Germany S02-Tunnel\n\n```\n# S02-Tunnel\nw:1833:000000::::89\n```\n\n#### Sky Germany V13 (NDS)\n\n```\n# V13\nw:09C4:000000::::46,58,90,95\n```\n\n#### HD+ (Nagra)\n\n```\n# HD+\nw:1830:000000::::92\nw:1830:003411::::92\nw:1830:008011::::92\n```\n\n#### ORF (CryptoWorks)\n\n```\n# CAMD3-Keys\nw:0D05:::::9C\n```", .status = 0 }, - { .param = "Whitelist", .config = "whitelist", .section = "", .text = "In whitelist mode, only explicitly allowed ECMs are processed:\n\n```\n# Allow only specific CAIDs\nw:1702\nw:09C4\nw:1830\n\n# Block everything else (implicit - no w: at end)\n```", .status = 0 }, - { .param = "Blacklist", .config = "whitelist", .section = "", .text = "In blacklist mode, all ECMs are allowed except those explicitly blocked:\n\n```\n# Block specific problematic services\ni:0500::1234\ni:0100::5678\n\n# Allow everything else\nw:\n```", .status = 0 }, - { .param = "Mixed", .config = "whitelist", .section = "", .text = "Combine whitelist and blacklist rules:\n\n```\n# Whitelist specific CAID with certain ECM lengths\nw:1702:000000::::93\n\n# Ignore problematic service\ni:0500::1234\n\n# Allow all other CAIDs\nw:\n```", .status = 0 }, - { .param = "Optimizing", .config = "whitelist", .section = "", .text = "1. **Be Specific**: Use specific rules to reduce processing overhead\n2. **Order Matters**: Place most frequently matched rules at the top\n3. **Minimize Entries**: Only include rules you actually need\n4. **Memory Consideration**: Avoid copying entire whitelist databases; use only what you need", .status = 0 }, - { .param = "Finding", .config = "whitelist", .section = "", .text = "To determine ECM lengths for your setup:\n\n1. Enable debug logging in OSCam\n2. Monitor ECM requests in the log\n3. Note the ECM lengths for services you want to whitelist\n4. Add appropriate entries to oscam.whitelist", .status = 0 }, - { .param = "Testing", .config = "whitelist", .section = "", .text = "1. Start with a permissive configuration (`w:` at the end)\n2. Add ignore rules for problematic services\n3. Monitor logs to verify filtering is working\n4. Gradually refine rules based on actual usage", .status = 0 }, - { .param = "Allow", .config = "whitelist", .section = "", .text = "```\nw:1702\n```", .status = 0 }, - { .param = "Allow", .config = "whitelist", .section = "", .text = "```\nw:1702:000000\n```", .status = 0 }, - { .param = "Allow", .config = "whitelist", .section = "", .text = "```\nw:09C4:000000::::46,58,90,95\n```", .status = 0 }, - { .param = "Ignore", .config = "whitelist", .section = "", .text = "```\ni:0500::1234\n```", .status = 0 }, - { .param = "Ignore", .config = "whitelist", .section = "", .text = "```\ni:::::2345\n```", .status = 0 }, - { .param = "Allow", .config = "whitelist", .section = "", .text = "```\nw:\n```", .status = 0 }, - { .param = "No", .config = "whitelist", .section = "", .text = "- Check if you have a catch-all `w:` rule at the end\n- Verify your whitelist rules match your actual CAIDs\n- Check for typos in hexadecimal values\n- Ensure file has proper permissions", .status = 0 }, - { .param = "Wrong", .config = "whitelist", .section = "", .text = "- Review rule order (first match wins)\n- Check for overlapping rules\n- Verify ECM lengths are correct\n- Enable debug logging to see which rules are matching", .status = 0 }, - { .param = "Performance", .config = "whitelist", .section = "", .text = "- Reduce number of rules\n- Use more specific rules to match faster\n- Remove unused entries\n- Consider using only essential whitelisting", .status = 0 }, - { .param = "oscam", .config = "whitelist", .section = "", .text = "The whitelist file works in conjunction with oscam.conf settings:\n\n```ini\n[global]\n# Enable ECM length filtering\necmwhitelist = /path/to/oscam.whitelist\n```", .status = 0 }, - { .param = "Related", .config = "whitelist", .section = "", .text = "- **oscam.conf**: Main configuration file\n- **oscam.services**: Service definitions\n- **oscam.user**: User-specific settings that may override whitelist behavior", .status = 0 }, - { .param = "Combining", .config = "whitelist", .section = "", .text = "```\n# Whitelist specific CAID, provider, and ECM length\nw:1702:000000::::93\n\n# Ignore specific CAID and service combination\ni:0500:123456:1234\n```", .status = 0 }, - { .param = "Provider-Specific", .config = "whitelist", .section = "", .text = "```\n# Allow HD+ with all providers\nw:1830:000000::::92\nw:1830:003411::::92\nw:1830:008011::::92\n\n# Block specific problematic provider\ni:0500:BADPROV\n```", .status = 0 }, - { .param = "Service-Level", .config = "whitelist", .section = "", .text = "```\n# Allow specific services only\nw:1702::SERVICE1\nw:1702::SERVICE2\n\n# Block all others (no catch-all w:)\n```", .status = 0 }, - { .param = "Required", .config = "services", .section = "", .text = "All parameters are required for each service definition:\n\n- **[service name]**: Unique name for the service group (section header)\n- **caid**: One or more CAIDs in hexadecimal, comma-separated\n- **provid**: One or more Provider IDs in hexadecimal, comma-separated\n- **srvid**: One or more Service IDs in hexadecimal, comma-separated", .status = 0 }, - { .param = "Optional", .config = "services", .section = "", .text = "These parameters were added in SVN revision 11588 (August 23, 2020):\n\n- **disablecrccws_only_for_exception**: Define service as exception for disablecrccws_only_for settings (0|1, default: 0)\n- **no_wait_time**: Define service as wait_time exception (0|1, default: 0)\n- **lg_only_exception**: Define service as localgenerated-only exception for cache exchange (0|1, default: 0)", .status = 0 }, - { .param = "HD", .config = "services", .section = "", .text = "```\n[hdplus]\ncaid = 1830,1843,1860,186A,186D\nprovid =\nsrvid = 0002,126E,126F,1519,151A,157C,157F,1581,183D,2774,2E9B,2EAF,307A,30D6,5274,6FEC,6FEE,EF10,EF11,EF14,EF15,EF16,EF17,EF74,EF75,EF76,EF77,EF78,EF79,EF7A,07E4,07D0,07EE,07F8\n```", .status = 0 }, - { .param = "Sky", .config = "services", .section = "", .text = "```\n[SAT-Sky-Starter-Paket]\ncaid = 098C,098D,09F0\nprovid =\nsrvid = 007F,0085,0194,0192,0016,0071,0191,00A8,0082,0077,0206,000D,0070,0017,0076,0093,007C,008E,006C,007E,0065,0088,007B\n```", .status = 0 }, - { .param = "Sky", .config = "services", .section = "", .text = "```\n[SAT-Sky-Sport-UHD]\ncaid = 098C,098D,09F0\nprovid =\nsrvid = 0228,0229\n```", .status = 0 }, - { .param = "Sky", .config = "services", .section = "", .text = "```\n[UM-Sky-Sport-Paket]\ncaid = 098E,1838,1850,1854,1868\nprovid =\nsrvid = 010C,0116,0120,012A,0134,013E,0148,0152,0102,010D,0011,0091,0090,008D,0072,0081\n```", .status = 0 }, - { .param = "ORF", .config = "services", .section = "", .text = "```\n[orfcw]\ncaid = 0D95,0D98\nprovid =\nsrvid = 32C9,32CA,32CB,32CC,32CD,32CE,32CF,32D0,32D1,32D2,32D3,32D6,32D4,33A7,4E27,33A5,332D,3337,132F,1330,33AC,33FD,1334,33FA,33FB,33FC,33F5,33F6,33F7,33F8,33F9,1331,33FC,14B8\n```", .status = 0 }, - { .param = "With", .config = "services", .section = "", .text = "```\n[special_service]\ncaid = 0100\nprovid = 000001\nsrvid = 5000,5001\ndisablecrccws_only_for_exception = 1\nno_wait_time = 1\nlg_only_exception = 1\n```\n\nThis service is configured with all exception flags enabled for special handling.", .status = 0 }, - { .param = "Separate", .config = "services", .section = "", .text = "```\n[sky_sport_channels]\ncaid = 098C,098D,09F0\nprovid =\nsrvid = 0228,0229,010C,0116\n\n[sky_cinema_channels]\ncaid = 098E,1838,1850,1854,1868\nprovid =\nsrvid = 0074,006B,008B\n\n[hd_basic_channels]\ncaid = 1830,1843,1860,186A,186D\nprovid =\nsrvid = EF10,EF11,EF74,EF75\n```", .status = 0 }, - { .param = "In", .config = "services", .section = "", .text = "```\n[account]\nuser = john\npwd = password\nservices = hdplus,SAT-Sky-Starter-Paket\n```\n\nUser \"john\" can only access channels defined in hdplus and SAT-Sky-Starter-Paket service groups.", .status = 0 }, - { .param = "In", .config = "services", .section = "", .text = "```\n[reader]\nlabel = myreader\nprotocol = internal\ndevice = /dev/sci0\nservices = orfcw,hdplus\n```\n\nThis reader is restricted to only serve channels defined in the orfcw and hdplus service groups.", .status = 0 }, - { .param = "Naming", .config = "services", .section = "", .text = "- Use descriptive, meaningful service names\n- Use lowercase with underscores (e.g., sky_de_sport)\n- Group related channels logically\n- Keep names short but clear", .status = 0 }, - { .param = "Organization", .config = "services", .section = "", .text = "- Group services by provider or package\n- Separate by content type (sports, movies, kids, etc.)\n- Use comments to document service groups\n- Keep related services together in the file", .status = 0 }, - { .param = "Maintenance", .config = "services", .section = "", .text = "- Document which channels belong to each service\n- Update service definitions when channel lineups change\n- Remove obsolete service definitions\n- Test service restrictions after changes", .status = 0 }, - { .param = "Performance", .config = "services", .section = "", .text = "- Stay within the 64-service limit per reader\n- Combine related channels into single services when possible\n- Avoid overly granular service definitions\n- Balance between flexibility and simplicity", .status = 0 }, - { .param = "User", .config = "services", .section = "", .text = "- Verify the service is assigned to the user in oscam.user\n- Check that the service definition includes the correct CAID/ProvID/SrvID\n- Ensure service names match exactly (case-sensitive)\n- Verify the reader has access to the service", .status = 0 }, - { .param = "Service", .config = "services", .section = "", .text = "- Check for typos in service names\n- Verify hexadecimal values are correct\n- Ensure all required parameters are present\n- Check for duplicate service names", .status = 0 }, - { .param = "64-Service", .config = "services", .section = "", .text = "- Consolidate similar services\n- Remove unused service definitions\n- Use broader service definitions\n- Consider splitting across multiple readers", .status = 0 }, - { .param = "enableled", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nLED-Support.\n\n```ini\nenableled = 0 # LED support disabled (default)\nenableled = 1 # LED support enabled for routers\nenableled = 2 # LED support enabled for Qbox HD\n```\n\n**Format:**\n```ini\nenableled = 0|1|2\n```\n\n**Example:**\n```ini\nenableled = 1\n```\n\n**Default:**\n```ini\nenableled = 0\n```", .status = 0 }, - { .param = "disablelog", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nSwitches logfile **off**.\n\n```ini\ndisablelog = 0 # log (default)\ndisablelog = 1 # no log\n```\n\n**Format:**\n```ini\ndisablelog = 0|1\n```\n\n**Example:**\n```ini\ndisablelog = 1\n```\n\n**Default:**\n```ini\ndisablelog = 0\n```", .status = 0 }, - { .param = "loghistorylines", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` or `MODULE_MONITOR` compilation flag)**\n\nNumber of log lines to keep in memory for display in WebIF status page.\n\n**Format:**\n```ini\nloghistorylines = count\n```\n\n**Example:**\n```ini\nloghistorylines = 512\n```\n\n**Default:**\n```ini\nloghistorylines = 256\n```\n\nMinimum value is 64. Values below 64 are adjusted automatically.", .status = 0 }, - { .param = "serverip", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nBind service to specified IP address.\n\n**Example:**\n```ini\nserverip = 192.168.178.1\n```\n\n**Default:**\n```ini\nserverip = # OSCam listens to all IPs\n```", .status = 0 }, - { .param = "logfile", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nLogging target.\n\n**Format:**\n```ini\nlogfile = [filename][;syslog][;stdout]\n```\n\nYou can define a maximum of one filename (not more!) and additionally to log to stdout or syslog (you can also only log to stdout or syslog and omit the filename).\n\n**Opportunities:**\n```ini\nlogfile = /var/log/oscam.log # file or linux device (for example /dev/tty)\nlogfile = syslog # log to syslogd\nlogfile = stdout # showing the log on the console\n```\n\n**Example:**\n```ini\nlogfile = /etc/oscam/logs/oscam.log;stdout\n```\n\n**Default:**\n```ini\nlogfile = /var/log/oscam.log\n```\n\n**Format logfile:**\n```\nCAID&ident/provider/length:checksum\n```", .status = 0 }, - { .param = "initial_debuglevel", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nSet the debuglevel on startup.\n\n**Example:**\n```ini\ninitial_debuglevel = 8\n```\n\n**Default:**\n```ini\ninitial_debuglevel = 0\n```", .status = 0 }, - { .param = "sysloghost", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nIf set, remote syslog server will be activated. Messages will be sent to this IPv4 address. If not set, remote syslog server does not work.\n\n**Format:**\n```ini\nsysloghost = IP_address\n```\n\n**Example:**\n```ini\nsysloghost = 192.168.1.167\n```\n\n**Default:**\n```ini\nsysloghost =\n```", .status = 0 }, - { .param = "syslogport", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nIf set *sysloghost*, remote syslog server will be activated. Messages will be sent to this port. If not set, port 514 is used as default.\n\n**Example:**\n```ini\nsyslogport = 515\n```\n\n**Default:**\n```ini\nsyslogport = 514\n```", .status = 0 }, - { .param = "logduplicatelines", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n```ini\nlogduplicatelines = 0 # enable detection of duplicate lines in logfile (default)\nlogduplicatelines = 1 # disable detection of duplicate lines in log file\n```\n\n**Format:**\n```ini\nlogduplicatelines = 0|1\n```\n\n**Example:**\n```ini\nlogduplicatelines = 1\n```\n\n**Default:**\n```ini\nlogduplicatelines = 0\n```", .status = 0 }, - { .param = "pidfile", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nChange PID file name and path. If default = oscam.pid in /tmp\n\n**Format:**\n```ini\npidfile = path/filename\n```\n\n**Example:**\n```ini\npidfile = /var/run/oscam.pid\n```\n\n**Default:**\n```ini\npidfile =\n```", .status = 0 }, - { .param = "disableuserfile", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nEven if a logfile is switched on (see logfile), the userfile can be turned off!\n\n```ini\ndisableuserfile = 0 # userfile (default)\ndisableuserfile = 1 # no userfile\n```\n\n**Format:**\n```ini\ndisableuserfile = 0|1\n```\n\n**Example:**\n```ini\ndisableuserfile = 1\n```\n\n**Default:**\n```ini\ndisableuserfile = 0\n```", .status = 0 }, - { .param = "disablemail", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nDisable saving NDS Videoguard mail messages from provider.\n\n```ini\ndisablemail = 0 # enabled\ndisablemail = 1 # disabled (default)\n```\n\n**Format:**\n```ini\ndisablemail = 0|1\n```\n\n**Example:**\n```ini\ndisablemail = 0\n```\n\n**Default:**\n```ini\ndisablemail = 1\n```", .status = 0 }, - { .param = "usrfileflag", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nSetting the logging-mode.\n\n```ini\nusrfileflag = 0 # Only login and logout will be logged (default)\nusrfileflag = 1 # Each zapping from client will be logged\n```\n\n**Format:**\n```ini\nusrfileflag = 0|1\n```\n\n**Example:**\n```ini\nusrfileflag = 1\n```\n\n**Default:**\n```ini\nusrfileflag = 0\n```", .status = 0 }, - { .param = "clienttimeout", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nValue in milliseconds for client process to wait for key.\n\n**Examples:**\n```ini\nclienttimeout = 10000 # after 10 seconds timeout\nclienttimeout = 10 # timeout after 10 milliseconds! (see note below)\nclienttimeout = 8 # timeout after 8000 milliseconds (= 8 seconds), see note below\n```\n\n**Default:**\n```ini\nclienttimeout = 5000 # timeout after 5000 milliseconds (= 5 seconds)\n```\n\n⚠️ **Attention:** Values < 10 (so 1 to 9) are multiplied with 1000, so a \"5\" results in 5000 ms.", .status = 0 }, - { .param = "fallbacktimeout", .config = "conf", .section = "global", .text = "**🔵 Parameter depends on setup/program version**\n\nMaximum waiting time of the cardserver in milliseconds for primary reader, before fallback reader (if any!) are questioned.\n\n**Example:**\n```ini\nfallbacktimeout = 1500\n```\n\n**Default:**\n```ini\nfallbacktimeout = 2500\n```\n\n⚠️ **Attention:** The value must be greater than the value in \"serialreadertimeout\", otherwise the default is used.", .status = 0 }, - { .param = "fallbacktimeout_percaid", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nTime falling back to CAID restricted fallback reader.\n\n**Format:**\n```ini\nfallbacktimeout_percaid = milliseconds\n```\n\n**Default:**\n```ini\nfallbacktimeout_percaid = 2500\n```", .status = 0 }, - { .param = "clientmaxidle", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nValue for client process being idle before disconnect in seconds.\n\n**Example:**\n```ini\nclientmaxidle = 200 # Disconnect after 200 seconds\nclientmaxidle = 0 # idle disconnect disabled\n```\n\n**Default:**\n```ini\nclientmaxidle = 120 # Disconnect after 120 seconds\n```", .status = 0 }, - { .param = "bindwait", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nValue in seconds to wait for bind request to complete. If OSCam within this time cannot bind, it finishes with \"Bind Request failed\".\n\nCauses may include:\n- Double assignment of ports\n- \"Crashed\" OSCam has not released the ports again\n- OSCam was started several times\n\n**Example:**\n```ini\nbindwait = 20 # waiting time 20 seconds\n```\n\n**Default:**\n```ini\nbindwait = 120 # waiting time 120 seconds\n```", .status = 0 }, - { .param = "netprio", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nNetwork priority for QoS (Quality of Service). This parameter sets two values:\n\n- **IPP (IP Precedence)**: Applied to `SO_PRIORITY` for system-internal socket prioritization\n- **DSCP (Differentiated Services Code Point)**: Applied to `IP_TOS` / `IPV6_TCLASS` for the TOS field in the IP packet header\n\nThis allows routers and network equipment to prioritize OSCam traffic appropriately.\n\n**Format:**\n```ini\nnetprio = 0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20\n```\n\n**Values:**\n\n- **0** (IPP 0, CS0): Best Effort (default)\n- **1** (IPP 1, CS1): Scavenger / Background\n- **2** (IPP 1, AF11): Assured Forwarding (Low Drop)\n- **3** (IPP 1, AF12): Assured Forwarding (Medium Drop)\n- **4** (IPP 1, AF13): Assured Forwarding (High Drop)\n- **5** (IPP 2, CS2): OAM (Operations/Administration/Management)\n- **6** (IPP 2, AF21): Assured Forwarding (Low Drop)\n- **7** (IPP 2, AF22): Assured Forwarding (Medium Drop)\n- **8** (IPP 2, AF23): Assured Forwarding (High Drop)\n- **9** (IPP 3, CS3): Broadcast Video\n- **10** (IPP 3, AF31): Assured Forwarding (Low Drop)\n- **11** (IPP 3, AF32): Assured Forwarding (Medium Drop)\n- **12** (IPP 3, AF33): Assured Forwarding (High Drop)\n- **13** (IPP 4, CS4): Real-Time Interactive\n- **14** (IPP 4, AF41): Assured Forwarding (Low Drop)\n- **15** (IPP 4, AF42): Assured Forwarding (Medium Drop)\n- **16** (IPP 4, AF43): Assured Forwarding (High Drop)\n- **17** (IPP 5, CS5): Signaling\n- **18** (IPP 5, EF): Expedited Forwarding (Voice/Video)\n- **19** (IPP 6, CS6): Network Control\n- **20** (IPP 7, CS7): Reserved (Highest Priority)\n\n**DSCP Classes Explained:**\n- **CS (Class Selector)**: Backward compatible with IP Precedence (CS0-CS7)\n- **AF (Assured Forwarding)**: AFxy where x=class (1-4), y=drop precedence (1=low, 2=medium, 3=high)\n- **EF (Expedited Forwarding)**: Low latency, low jitter - ideal for real-time traffic\n\n**Example:**\n```ini\nnetprio = 18 # EF - Expedited Forwarding, best for time-critical CW delivery\n```\n\n**Default:**\n```ini\nnetprio = 0 # CS0 - Best Effort, no special treatment\n```\n\n⚠️ **Note:** The effectiveness depends on your network equipment supporting and respecting DSCP markings. Many consumer routers ignore these values.", .status = 0 }, - { .param = "sleep", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nTime waiting for inactive users in minutes, can be overwritten per user in oscam.user.\n\n**Example:**\n```ini\nsleep = 5 # waiting time 5 minutes\n```\n\n**Default:**\n```ini\nsleep = # no waiting time\n```", .status = 0 }, - { .param = "unlockparental", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**Only Seca and Viaccess**\n\nUnlock parental mode option to disable PIN code request for adult movie. In order to work properly, this option may require that you define the card PIN code in your card reader configuration.\n\n**Example:**\n```ini\nunlockparental = 1 # parental lock mode disabled\n```\n\n**Default:**\n```ini\nunlockparental = 0 # parental lock mode enabled\n```", .status = 0 }, - { .param = "nice", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**System priority**\n\nOSCam requires almost no CPU-power. But if CPU-power is required, it should be available immediately. Values between 20 and -20 are possible. 20 = low, -20 = very high. If this parameter is commented out (#), this function is not called. Important for example for dbox2, if the error messages \"*relocation error:setpriority*\". See [Priority Scheduling](http://de.wikipedia.org/wiki/Prioritätsscheduling).\n\n**Example:**\n```ini\nnice = -1\n```\n\n**Default:**\n```ini\nnice = 99\n```", .status = 0 }, - { .param = "maxlogsize", .config = "conf", .section = "global", .text = "**🔴 Required parameter**\n\nMaximum size of logfiles in KBytes. This is especially important for servers with only a small amount of memory (dbox2). Therefore it is strongly recommended to determine carefully that size at such servers. Not infrequently a system \"bursts\" because the logfile uncontrolled large scale adopted!\n\n**Example:**\n```ini\nmaxlogsize = 20 # Logfile reaches to 20 KBytes\nmaxlogsize = 0 # Logfile unlimited\n```\n\n**Default:**\n```ini\nmaxlogsize = 10 # Logfile reaches to 10 KBytes\n```", .status = 0 }, - { .param = "waitforcards", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nWait for local SCs on startup before opening network ports.\n\n**Example:**\n```ini\nwaitforcards = 0 # don't wait\n```\n\n**Default:**\n```ini\nwaitforcards = 1 # wait\n```", .status = 0 }, - { .param = "waitforcards_extra_delay", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nAdditional delay in milliseconds after waiting for local SCs on startup before opening network ports.\n\n**Format:**\n```ini\nwaitforcards_extra_delay = milliseconds\n```\n\n**Default:**\n```ini\nwaitforcards_extra_delay = 500\n```", .status = 0 }, - { .param = "preferlocalcards", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nTry decoding on local cards first.\n\n**Example:**\n```ini\npreferlocalcards = 0 # local cards are used like remote reader\npreferlocalcards = 1 # prefer CacheEx sources\npreferlocalcards = 2 # prefer local cards\n```\n\n**Default:**\n```ini\npreferlocalcards = 1 # prefer CacheEx sources\n```", .status = 0 }, - { .param = "readerrestartseconds", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nWaiting time in seconds between restarts.\n\n**Example:**\n```ini\nreaderrestartseconds = 10 # waiting time 10 seconds\nreaderrestartseconds = 0 # no restarts!\n```\n\n**Default:**\n```ini\nreaderrestartseconds = 5 # waiting time 5 seconds\n```", .status = 0 }, - { .param = "dropdups", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nMode for duplicate client connections.\n\n```ini\ndropdups = 0 # mark client as duplicate, but don't disconnect them (default)\ndropdups = 1 # drop duplicate connections instead of marking as duplicate\n```\n\n**Format:**\n```ini\ndropdups = 0|1\n```\n\n**Example:**\n```ini\ndropdups = 1\n```\n\n**Default:**\n```ini\ndropdups = 0\n```", .status = 0 }, - { .param = "SIGHUP", .config = "conf", .section = "global", .text = "The following parameters control what OSCam reloads when it receives a SIGHUP signal. When enabled, sending SIGHUP to the OSCam process will reload the corresponding configuration without requiring a full restart.", .status = 0 }, - { .param = "reload_useraccounts", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nReload user accounts (oscam.user) on SIGHUP signal.\n\n**Format:**\n```ini\nreload_useraccounts = 0|1\n```\n\n**Example:**\n```ini\nreload_useraccounts = 1\n```\n\n**Default:**\n```ini\nreload_useraccounts = 0\n```", .status = 0 }, - { .param = "reload_readers", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nReload readers (oscam.server) on SIGHUP signal.\n\n**Format:**\n```ini\nreload_readers = 0|1\n```\n\n**Example:**\n```ini\nreload_readers = 1\n```\n\n**Default:**\n```ini\nreload_readers = 0\n```", .status = 0 }, - { .param = "reload_provid", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nReload provider IDs (oscam.provid) on SIGHUP signal.\n\n**Format:**\n```ini\nreload_provid = 0|1\n```\n\n**Example:**\n```ini\nreload_provid = 1\n```\n\n**Default:**\n```ini\nreload_provid = 0\n```", .status = 0 }, - { .param = "reload_services_ids", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nReload services IDs (oscam.srvid / oscam.srvid2) on SIGHUP signal.\n\n**Format:**\n```ini\nreload_services_ids = 0|1\n```\n\n**Example:**\n```ini\nreload_services_ids = 1\n```\n\n**Default:**\n```ini\nreload_services_ids = 0\n```", .status = 0 }, - { .param = "reload_tier_ids", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nReload tier IDs (oscam.tiers) on SIGHUP signal.\n\n**Format:**\n```ini\nreload_tier_ids = 0|1\n```\n\n**Example:**\n```ini\nreload_tier_ids = 1\n```\n\n**Default:**\n```ini\nreload_tier_ids = 0\n```", .status = 0 }, - { .param = "reload_fakecws", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nReload fake control words (oscam.fakecws) on SIGHUP signal.\n\n**Format:**\n```ini\nreload_fakecws = 0|1\n```\n\n**Example:**\n```ini\nreload_fakecws = 1\n```\n\n**Default:**\n```ini\nreload_fakecws = 0\n```", .status = 0 }, - { .param = "reload_ac_stat", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nReload anti-cascading statistics on SIGHUP signal.\n\n**Format:**\n```ini\nreload_ac_stat = 0|1\n```\n\n**Example:**\n```ini\nreload_ac_stat = 1\n```\n\n**Default:**\n```ini\nreload_ac_stat = 0\n```", .status = 0 }, - { .param = "reload_log", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nReopen log file on SIGHUP signal. Useful for log rotation.\n\n**Format:**\n```ini\nreload_log = 0|1\n```\n\n**Example:**\n```ini\nreload_log = 1\n```\n\n**Default:**\n```ini\nreload_log = 0\n```", .status = 0 }, - { .param = "block_same_ip", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nReject looping ECMs from clients to reader with the same IP address.\n\n```ini\nblock_same_ip = 0 # no reject\nblock_same_ip = 1 # reject looping ECMs (default)\n```\n\n**Format:**\n```ini\nblock_same_ip = 0|1\n```\n\n**Example:**\n```ini\nblock_same_ip = 0\n```\n\n**Default:**\n```ini\nblock_same_ip = 1\n```", .status = 0 }, - { .param = "block_same_name", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nReject looping ECMs from clients to reader with the same name.\n\n```ini\nblock_same_name = 0 # no reject\nblock_same_name = 1 # reject looping ECMs (default)\n```\n\n**Format:**\n```ini\nblock_same_name = 0|1\n```\n\n**Example:**\n```ini\nblock_same_name = 0\n```\n\n**Default:**\n```ini\nblock_same_name = 1\n```", .status = 0 }, - { .param = "usrfile", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nSet a name for userfile.\n\n**Format of the userfile:**\n```\ndate\ntime\nCWs per second\nusername\nIP address of client\nTCP/IP port\nCWs found\nCWs from cache\nCWs not found\nCWs ignored\nCWs timeout\nCWs tunneled\nlogin time in UNIX/POSIX format\nlogout time in UNIX/POSIX format\nprotocol\n```\n\n**Example:**\n```ini\nusrfile = userfile\n```\n\n**Default:**\n```ini\nusrfile = 0\n```", .status = 0 }, - { .param = "mailfile", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nDefine file saving NDS Videoguard mail messages from provider.\n\n**Default:**\n```ini\nmailfile = # none\n```", .status = 0 }, - { .param = "cwlogdir", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nA path for CW logging can be configured here. The path is relative to the work directory and must exist. Otherwise no logs are created and no errors are reported.\n\nCWs (control words) are the answers of the card which decrypts a certain channel for some seconds before the next CW is transmitted. The CW log file can be used for delayed decoding of this channel. This is also called offline decoding.\n\nOSCam creates a new `*.cwl` file for each channel and each day. The file name contains the date, service ID and service name, e.g., `110808_I000B_Sky_Cinema_+1.cwl` with these contents:\n\n```\n# OSCam cardserver v0.99.4 - http://streamboard.gmc.to:8001/oscam/wiki\n# control word log file for use with tsdec offline decrypter\n# DATE 2011-08-08, TIME 23:49:10, TZ CEST\n# CAID 0x1702, SID 0x000B, SERVICE \"Sky_Cinema_+1\"\n1 9E E3 BB 3C A4 C3 BE 25 # 23:49:10\n0 D0 24 B3 A7 95 82 3B 52 # 23:49:17\n1 A9 76 35 54 37 38 F3 62 # 23:49:23\n0 55 70 87 4C 22 26 C4 0C # 23:49:30\n1 F0 16 22 28 36 3A 03 73 # 23:49:38\n0 5D 83 44 24 8F C7 5D B3 # 23:49:44\n```\n\nAll CWs are logged if at least one user watches the channel. Please choose a path with enough space, since per day and channel some 10KB of data are created. A script that moves/deletes the log files regularly is recommended.\n\n**Example:**\n```ini\ncwlogdir = /var/log/\n```\n\n**Default:**\n```ini\ncwlogdir = # no path for cw-log, logging disabled\n```", .status = 0 }, - { .param = "emmlogdir", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nSetting a path for EMM-log. You can define with the \"saveemm-*\"-Parameters in oscam.server which EMMs should be logged.\n\n**Example:**\n```ini\nemmlogdir = /var/log/\n```\n\n**Default:**\n```ini\nemmlogdir = # the config folder will be used for emm logging\n```", .status = 0 }, - { .param = "lb_mode", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nLoadbalance mode.\n\n```ini\nlb_mode = 0 # loadbalance disabled, ECMs go to all readers (default)\nlb_mode = 1 # fastest reader first, after 5 ECMs the reader with the fastest\n # response time will be selected\nlb_mode = 2 # oldest reader first, reader with the longest no answer\nlb_mode = 3 # lowest usage level, the usage level will be calculated by the\n # sum of 5 ECMs response times, the higher a reader is busy,\n # the higher is usage level\nlb_mode = 10 # LB is switched off, but statistics are built\n```\n\n**Format:**\n```ini\nlb_mode = 0|1|2|3|10\n```\n\n**Example:**\n```ini\nlb_mode = 1\n```\n\n**Default:**\n```ini\nlb_mode = 0\n```", .status = 0 }, - { .param = "lb_save", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nSave autoloadbalance statistics (counts). To save CPU power a minimum count of 100 is recommended.\n\n**Example:**\n```ini\nlb_save = 100 # counts of ECMs after statistics are saved\n```\n\n**Default:**\n```ini\nlb_save = 0 # no save\n```", .status = 0 }, - { .param = "lb_nbest_readers", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nSet count of best readers for loadbalancing.\n\n**Example:**\n```ini\nlb_nbest_readers = 2 # requests always go to two readers\n```\n\n**Default:**\n```ini\nlb_nbest_readers = 1 # requests go to one reader\n```", .status = 0 }, - { .param = "lb_nfb_readers", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nSet count of fallback readers for loadbalancing.\n\n**Example:**\n```ini\nlb_nfb_readers = 2 # two fallback readers\n```\n\n**Default:**\n```ini\nlb_nfb_readers = 1 # one fallback reader\n```", .status = 0 }, - { .param = "lb_min_ecmcount", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nMinimal ECM count to evaluate loadbalancing values.\n\n**Example:**\n```ini\nlb_min_ecmcount = 2 # 2 counts\n```\n\n**Default:**\n```ini\nlb_min_ecmcount = 5 # 5 counts\n```", .status = 0 }, - { .param = "lb_max_ecmcount", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nMaximum ECM count before resetting loadbalancing values.\n\n**Example:**\n```ini\nlb_max_ecmcount = 200 # 200 counts\n```\n\n**Default:**\n```ini\nlb_max_ecmcount = 500 # 500 counts\n```", .status = 0 }, - { .param = "lb_reopen_seconds", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nTime in seconds between retrying failed readers/CAIDs/providers/services.\n\n**Example:**\n```ini\nlb_reopen_seconds = 500 # retry after 500 seconds\n```\n\n**Default:**\n```ini\nlb_reopen_seconds = 900 # retry after 900 seconds\n```", .status = 0 }, - { .param = "lb_reopen_invalid", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\n```ini\nlb_reopen_invalid = 0 # E_INVALID will be blocked until statistics has been cleaned\nlb_reopen_invalid = 1 # default\n```\n\n**Format:**\n```ini\nlb_reopen_invalid = 0|1\n```\n\n**Example:**\n```ini\nlb_reopen_invalid = 0\n```\n\n**Default:**\n```ini\nlb_reopen_invalid = 1\n```", .status = 0 }, - { .param = "lb_force_reopen_always", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nForce reopening immediately all failing readers if no matching reader was found.\n\n```ini\nlb_force_reopen_always = 0 # default\nlb_force_reopen_always = 1 # force reopening immediately\n```\n\n**Format:**\n```ini\nlb_force_reopen_always = 0|1\n```\n\n**Example:**\n```ini\nlb_force_reopen_always = 1\n```\n\n**Default:**\n```ini\nlb_force_reopen_always = 0\n```", .status = 0 }, - { .param = "lb_retrylimit", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nRetry next readers **only** if response time is higher than lb_retrylimit in milliseconds.\n\n**Example:**\n```ini\nlb_retrylimit = 500 # retry next reader only if response time is higher than 500 ms\n```\n\n**Default:**\n```ini\nlb_retrylimit = 800\n```", .status = 0 }, - { .param = "lb_stat_cleanup", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nHours after the loadbalancing statistics will be deleted.\n\n**Default:**\n```ini\nlb_stat_cleanup = 336\n```", .status = 0 }, - { .param = "lb_max_readers", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nRestrict the reader count to limit during learning.\n\n**Format:**\n```ini\nlb_max_readers = limit\n```\n\n```ini\nlb_max_readers = 0 # unlimited (default)\nlb_max_readers = x # restrict loadbalancer readers to limit x (number)\n```", .status = 0 }, - { .param = "lb_auto_betatunnel", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nEnable automatic Betacrypt tunneling for CAIDs 1801, 1833, 1834 and 1835 in loadbalancing mode.\n\n```ini\nlb_auto_betatunnel = 0 # disabled\nlb_auto_betatunnel = 1 # enabled (default)\n```\n\n**Format:**\n```ini\nlb_auto_betatunnel = 0|1\n```\n\n**Example:**\n```ini\nlb_auto_betatunnel = 0\n```\n\n**Default:**\n```ini\nlb_auto_betatunnel = 1\n```\n\n⚠️ **Attention:** Betacrypt definition in oscam.user with betatunnel will be preferred!", .status = 0 }, - { .param = "lb_auto_betatunnel_mode", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nSet mode for automatic Betacrypt tunneling.\n\n```ini\nlb_auto_betatunnel_mode = 0 # CAID 18XX tunneling to CAID 17X2 only (default)\nlb_auto_betatunnel_mode = 1 # CAID 18XX tunneling to CAID 17X2 and CAID 17X2\n # tunneling to CAID 18XX (CAID 1833/1801)\nlb_auto_betatunnel_mode = 2 # CAID 18XX tunneling to CAID 17X2 and CAID 17X2\n # tunneling to CAID 18XX (CAID 1833/1834)\nlb_auto_betatunnel_mode = 3 # CAID 18XX tunneling to CAID 17X2 and CAID 17X2\n # tunneling to CAID 18XX (CAID 1833/1835)\nlb_auto_betatunnel_mode = 4 # CAID 17X2 tunneling to CAID 18XX (CAID 1833/1801 only)\nlb_auto_betatunnel_mode = 5 # CAID 17X2 tunneling to CAID 18XX (CAID 1833/1834 only)\nlb_auto_betatunnel_mode = 6 # CAID 17X2 tunneling to CAID 18XX (CAID 1833/1835 only)\n```\n\n**Format:**\n```ini\nlb_auto_betatunnel_mode = 0|1|2|3|4|5|6\n```\n\n**Example:**\n```ini\nlb_auto_betatunnel_mode = 1\n```\n\n**Default:**\n```ini\nlb_auto_betatunnel_mode = 0\n```", .status = 0 }, - { .param = "lb_auto_betatunnel_prefer_beta", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nSet preference for automatic selection of Betacrypt/Nagravision.\n\n**Format:**\n```ini\nlb_auto_betatunnel_prefer_beta = number\n```\n\n```ini\nlb_auto_betatunnel_prefer_beta = 0 # disabled (default)\nlb_auto_betatunnel_prefer_beta = 1 # always Betacrypt\nlb_auto_betatunnel_prefer_beta = 105 # represents the middle\nlb_auto_betatunnel_prefer_beta = 200 # always Nagravision\n```", .status = 0 }, - { .param = "lb_savepath", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nFilename for saving loadbalancing statistics.\n\n**Default:**\n```ini\nlb_savepath = /tmp/.oscam/stat\n```", .status = 0 }, - { .param = "lb_retrylimits", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nLoadbalancing retry limit time per CAID in milliseconds, wildcard CAIDs with 2-digit CAIDs possible.\n\n**Format:**\n```ini\nlb_retrylimits = CAID1:time1[,CAID2:time2]...\n```\n\n**Example:**\n```ini\nlb_retrylimits = 12:0100,34:0200,5678:0300 # wildcard CAIDs 12xx and 34xx\n```\n\n**Default:** none", .status = 0 }, - { .param = "lb_nbest_percaid", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nSet count of best readers per CAIDs for loadbalancing, wildcard CAIDs with two-digit CAIDs possible.\n\n**Format:**\n```ini\nlb_nbest_percaid = CAID1:count[,CAID2:count]...\n```\n\n**Example:**\n```ini\nlb_nbest_percaid = 0100:4,0200:3,03:2,04:1 # wildcard CAIDs 03xx and 04xx\n```\n\n**Default:** none", .status = 0 }, - { .param = "lb_noproviderforcaid", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nIgnore provider information CAIDs to reduce statistic data, wildcard CAIDs with two-digit CAIDs possible.\n\n**Format:**\n```ini\nlb_noproviderforcaid = CAID1[,CAID2]...\n```\n\n**Example:**\n```ini\nlb_noproviderforcaid = 12,34,5678 # wildcard CAIDs 12xx and 34xx\n```\n\n**Default:** none", .status = 0 }, - { .param = "lb_auto_timeout", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nEnable automatic timeout based on load balancing statistics.\n\n```ini\nlb_auto_timeout = 0 # default\nlb_auto_timeout = 1 # enable automatic timeout\n```\n\n**Format:**\n```ini\nlb_auto_timeout = 0|1\n```\n\n**Example:**\n```ini\nlb_auto_timeout = 1\n```\n\n**Default:**\n```ini\nlb_auto_timeout = 0\n```", .status = 0 }, - { .param = "lb_auto_timeout_p", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nPercent added to average time as timeout time.\n\n**Format:**\n```ini\nlb_auto_timeout_p = percent\n```\n\n**Default:**\n```ini\nlb_auto_timeout_p = 30\n```", .status = 0 }, - { .param = "lb_auto_timeout_t", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_LB` compilation flag)**\n\nMinimal time added to average time as timeout time.\n\n**Format:**\n```ini\nlb_auto_timeout_t = milliseconds\n```\n\n**Default:**\n```ini\nlb_auto_timeout_t = 300\n```", .status = 0 }, - { .param = "double_check_caid", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nECM will be sent to two or more readers with the same SC and the CWs will be verified against each other for defined CAID or first two bytes of CAID. `lb_nbest_readers` must be set to 2 or higher.\n\n**Format:**\n```ini\ndouble_check_caid = [CAID1|first two digits of CAID1],[CAID2|first two digits of CAID2]...\n```\n\n**Default:** none", .status = 0 }, - { .param = "ecmfmt", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nDefine ECM log format.\n\n**Format:**\n```ini\necmfmt = format\n```\n\n**Possible variables:**\n```\nc = CAID\nd = PID\ne = CSP hash\ng = ID of origin gbox peer\nh = checksum\ni = Channel ID\nj = distance of gbox and CCcam hops\nl = length\no = ONID\np = provider ID\ns = service ID\nt = tier ID (this ID will be replaced with the tier-description from oscam.tiers if found)\nw = CW\ny = payload (short, 3 bytes)\nY = payload (long, 6 bytes)\n```\n\nUse a value as prefix to hide variable with this value, control characters will be escaped by \"\\\\\".\n\n**Example:**\n```ini\necmfmt = c&0p/i/d/s/l:h.e_w HOP:j # hide provider ID if 0\n```\n\n**Default:**\n```ini\necmfmt = c&p/i/s/l:h\n```", .status = 0 }, - { .param = "resolvegethostbyname", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nSet mode for DNS resolving. These are different libc calls to resolve DNS names and some older systems have problems with the newer implementation *getaddrinfo* (getaddrinfo is also threadsafe whereas *gethostbyname* is not and thus it has some locks around) or have stripped them from their images (dbox2 was such a candidate) even though it is available at compile time.\n\n```ini\nresolvegethostbyname = 0 # getaddrinfo (default)\nresolvegethostbyname = 1 # gethostbyname\n```\n\n**Format:**\n```ini\nresolvegethostbyname = 0|1\n```\n\n**Example:**\n```ini\nresolvegethostbyname = 1\n```\n\n**Default:**\n```ini\nresolvegethostbyname = 0\n```", .status = 0 }, - { .param = "failbantime", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nTime for IP based blocking for clients with an invalid login attempt in minutes.\n\n**Example:**\n```ini\nfailbantime = 5 # IP will be blocked for 5 minutes\n # New logins are denied\n # No clientthread will be created\n```\n\n**Default:**\n```ini\nfailbantime = 0 # failban off (default)\n```", .status = 0 }, - { .param = "failbancount", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nNumber of allowed failed attempts with incorrect data.\n\n```ini\nfailbancount = 0 # IP is blocked on the first try with incorrect data (default)\nfailbancount = n # number of allowed attempts\n```\n\nIf within **failbantime** more than in **failbancount** allowed trials are registered, the IP for the remainder of failbantime is locked. After a period of failbantime, full failbancount is available again. Failbancount is thus a relaxation of rules!", .status = 0 }, - { .param = "suppresscmd08", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nTell camd35 [cs3.57x]-clients not to request again for rejected CAID, service ID and provider ID combination.\n\n```ini\nsuppresscmd08 = 0 # enabled (default)\nsuppresscmd08 = 1 # disabled\n```\n\n**Format:**\n```ini\nsuppresscmd08 = 0|1\n```\n\n**Example:**\n```ini\nsuppresscmd08 = 1\n```\n\n**Default:**\n```ini\nsuppresscmd08 = 0\n```\n\nCan be overwritten in oscam.user!\n\nMore information: [Streamboard-Thread](http://www.streamboard.tv/wbb2/thread.php?threadid=27459)", .status = 0 }, - { .param = "getblockemmauprovid", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nGet provider ID from CAID for blocking EMM AU updates.\n\n**Format:**\n```ini\ngetblockemmauprovid = 0|1\n```\n\n**Example:**\n```ini\ngetblockemmauprovid = 1\n```\n\n**Default:**\n```ini\ngetblockemmauprovid = 0\n```", .status = 0 }, - { .param = "double_check", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nECM will be sent to two or more readers with the same SC and the CWs will be verified against each other. `lb_nbest_readers` must be set to 2 or higher.\n\n**Example:**\n```ini\ndouble_check = 1 # on\n```\n\n**Default:**\n```ini\ndouble_check = 0 # off\n```", .status = 0 }, - { .param = "disablecrccws", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nSkip CW checksum test globally. Some providers send CWs that don't pass the checksum test but are still valid.\n\n**Format:**\n```ini\ndisablecrccws = 0|1\n```\n\n**Example:**\n```ini\ndisablecrccws = 1\n```\n\n**Default:**\n```ini\ndisablecrccws = 0\n```", .status = 0 }, - { .param = "disablecrccws_only_for", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\nSkip CW checksum test only for specific CAIDs/providers/services. Use this for selective disabling instead of the global `disablecrccws` option.\n\n**Format:**\n```ini\ndisablecrccws_only_for = CAID1[:ident1][,CAID2[:ident2]]...\n```\n\n**Example:**\n```ini\ndisablecrccws_only_for = 0100:000030,0500\n```\n\n**Default:** none", .status = 0 }, - { .param = "cacheex_srcname_webif", .config = "conf", .section = "global", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nDisplay CacheEx source name in WebIF status.\n\n**Format:**\n```ini\ncacheex_srcname_webif = 0|1\n```\n\n**Example:**\n```ini\ncacheex_srcname_webif = 1\n```\n\n**Default:**\n```ini\ncacheex_srcname_webif = 0\n```", .status = 0 }, - { .param = "CW", .config = "conf", .section = "cache", .text = "Cache of CWs which are saved to detect/drop old CWs arriving via CacheEx.\nTo enable this feature, you have to define `cw_cache_size` or `cw_cache_memory` to set the cache-size and `cw_cache_settings` to define for what CWs which action is taken.\nIf `cw_cache_size` or `cw_cache_memory` is defined, the default is that incoming known CWs older than 15 seconds are dropped, because they are useless.", .status = 0 }, - { .param = "ECM", .config = "conf", .section = "cache", .text = "Cache of ECMs which are saved to detect/drop old ECMs.\nIf you are facing problems with getting old ECMs, with this feature you are able to drop known ECMs. To enable this feature, you have to define `ecm_cache_size` or `ecm_cache_memory` to set the cache-size.", .status = 0 }, - { .param = "delay", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\nValue to delay cached requests.\n\n**Example:**\n```ini\ndelay = 300\n```\n\n**Default:**\n```ini\ndelay = 0\n```", .status = 0 }, - { .param = "max_time", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\nMaximum time CWs resist in cache after 1st client request (seconds). The time must be 2 seconds higher than the parameter clienttimeout.\n\n**Format:**\n```ini\nmax_time = seconds\n```\n\n**Default:**\n```ini\nmax_time = 15\n```", .status = 0 }, - { .param = "cw_cache_size", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nCount of max. CWs for cw_cache.\n\n**Default:**\n```ini\ncw_cache_size = 0\n```", .status = 0 }, - { .param = "cw_cache_memory", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nSize (in MB) of the cw_cache.\n\n**Default:**\n```ini\ncw_cache_memory = 0\n```", .status = 0 }, - { .param = "cw_cache_settings", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\n**Format:**\n```ini\ncw_cache_settings = caid[&mask][@provid][$servid]:mode:timediff_old_cw[,n]\n```\n\n**Mode:**\n- `1` = just write logs @ log-level 8192\n- `2` = drop CWs which match this rule & write logs @ log-level 8192\n\n**timediff_old_cw:**\n- `time` = time in milliseconds after a known CW is detected/dropped\n\n**Example:**\n```ini\ncw_cache_settings = 0:2:1500,BEEF@012345:2:620,1337:1:170\n```\n\n- For all CWs not matching any other rule → drop if the CW is known for more than 1500ms\n- Drop CWs of caid BEEF with provid 012345, if they are known for more than 620ms\n- Log CWs of caid 1337 with all provids, if they are known for more than 170ms\n\n**Default:**\n```ini\ncw_cache_settings = # disabled\n```", .status = 0 }, - { .param = "ecm_cache_size", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nCount of max. ECMs for ecm_cache.\n\n**Default:**\n```ini\necm_cache_size = 0\n```", .status = 0 }, - { .param = "ecm_cache_memory", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nSize (in MB) of the ecm_cache.\n\n**Default:**\n```ini\necm_cache_memory = 0\n```", .status = 0 }, - { .param = "ecm_cache_droptime", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nTime in seconds after a known ECM is dropped with return-code E_INVALID.\n\n**Default:**\n```ini\necm_cache_droptime = 0\n```", .status = 0 }, - { .param = "max_hit_time", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\nMaximum time for cache exchange hits resists in cache for evaluating wait_time (in seconds).\n\n**Default:**\n```ini\nmax_hit_time = 15\n```", .status = 0 }, - { .param = "wait_time", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\nWait time for cache exchange (mode 2 & 3 only!) and Cardserver proxy before sending ECM to reader or proxy.\n\n**Format:**\n```ini\nwait_time = milliseconds\n```\n\n**Example:**\n```ini\nwait_time = 0:50:250,0200@00009X:50:150:950,0500@000001:150:1602&ffdf:1200\n```\n\n**Default:**\n```ini\nwait_time = # none\n```", .status = 0 }, - { .param = "cacheex_mode1_delay", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\nDelay in milliseconds for asking cache exchange mode 1 readers.\n\n**Format:**\n```ini\ncacheex_mode1_delay = CAID1:time[,CAID2:time]...\n```\n\n**Default:** none", .status = 0 }, - { .param = "cacheexenablestats", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\nEnable statistics for cache exchange mode.\n\n```ini\ncacheexenablestats = 0 # disabled (default)\ncacheexenablestats = 1 # enable statistics\n```\n\n**Format:**\n```ini\ncacheexenablestats = 0|1\n```\n\n**Example:**\n```ini\ncacheexenablestats = 1\n```\n\n**Default:**\n```ini\ncacheexenablestats = 0\n```\n\n⚠️ **Warning:** Please consider memory consumption!", .status = 0 }, - { .param = "cacheex_dropdiffs", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nDrop incoming not-localgenerated-flagged CWs which differ from the first CW.\n\n```ini\ncacheex_dropdiffs = 0 # default\ncacheex_dropdiffs = 1 # drop different CWs\n```\n\n**Format:**\n```ini\ncacheex_dropdiffs = 0|1\n```\n\n**Example:**\n```ini\ncacheex_dropdiffs = 1\n```\n\n**Default:**\n```ini\ncacheex_dropdiffs = 0\n```", .status = 0 }, - { .param = "cacheex_push_lg_groups", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nPush all lg-flagged CWs to this/these group/s, without checking the groupmembership of the peer.\n\n**Format:**\n```ini\ncacheex_push_lg_groups = 1[,n]\n```\n\n**Default:**\n```ini\ncacheex_push_lg_groups = # none\n```", .status = 0 }, - { .param = "cacheex_lg_only_remote_settings", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nPossibility to deny cacheex-receiver/client (cx2: user / cx3: reader) to overwrite the following settings @ cacheex-sending-instance:\n- `cacheex_localgenerated_only`\n- `cacheex_lg_only_tab`\n\nIt makes sense if you want to force your local settings. If the user/reader isn't allowed to overwrite your values:\n- It is still possible for the cacheex-receiver to set `cacheex_localgenerated_only=1`, if the user/reader defines `cacheex_localgenerated_only_in=1`; but it is only @ cacheex-sending-instance possible to disable it\n- It is still possible for the cacheex-receiver to add `cacheex_lg_only_tab`, if the user/reader defines `cacheex_lg_only_in_tab=1234,1337`; but it is only merged to the sender-instance `cacheex_lg_only_tab` values\n\nIf `cacheex_lg_only_remote_settings` @oscam.conf is enabled, the user/reader-settings are ignored. If `cacheex_lg_only_remote_settings` @oscam.conf is disabled, the user/reader-settings are used.\n\n```ini\ncacheex_lg_only_remote_settings = 0 # default (opt-out)\ncacheex_lg_only_remote_settings = 1\n```\n\n**Format:**\n```ini\ncacheex_lg_only_remote_settings = 0|1\n```\n\n**Example:**\n```ini\ncacheex_lg_only_remote_settings = 1\n```\n\n**Default:**\n```ini\ncacheex_lg_only_remote_settings = 0\n```", .status = 0 }, - { .param = "cacheex_localgenerated_only", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nForward only CWs which are flagged as localgenerated. Here in oscam.conf, the default value is set; user/reader-settings are prioritized.\n\n```ini\ncacheex_localgenerated_only = 0 # default (opt-in)\ncacheex_localgenerated_only = 1\n```\n\n**Format:**\n```ini\ncacheex_localgenerated_only = 0|1\n```\n\n**Example:**\n```ini\ncacheex_localgenerated_only = 1\n```\n\n**Default:**\n```ini\ncacheex_localgenerated_only = 0\n```", .status = 0 }, - { .param = "cacheex_localgenerated_only_caid", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nCAID table for localgenerated-only filter. Forward only locally generated CWs for these CAIDs. Deprecated: use `cacheex_lg_only_tab` instead.\n\n**Format:**\n```ini\ncacheex_localgenerated_only_caid = CAID1[,CAID2]...\n```\n\n**Example:**\n```ini\ncacheex_localgenerated_only_caid = 0100,0500,1702\n```\n\n**Default:**\n```ini\ncacheex_localgenerated_only_caid =\n```", .status = 0 }, - { .param = "cacheex_lg_only_tab", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nForward only CWs which are lg-flagged for these list of caid/provid(s). Here in oscam.conf, the default value is set; user/reader-settings are prioritized.\n\nIf provid `FFFFFE` is set, all provids for this caid are valid!\n\n**Format:**\n```ini\ncacheex_lg_only_tab = caid1:provid1[,provid2];caid2:provid1;\n```", .status = 0 }, - { .param = "cacheex_lg_only_in_aio_only", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nUse drop lg-only settings (`cacheex_localgenerated_only_in` & `cacheex_lg_only_in_tab`) only if peer is detected as cx-aio-patched or svn >= 11588. Here in oscam.conf, the default value is set; user/reader-settings are prioritized.\n\n```ini\ncacheex_lg_only_in_aio_only = 0 # default (opt-in)\ncacheex_lg_only_in_aio_only = 1\n```\n\n**Format:**\n```ini\ncacheex_lg_only_in_aio_only = 0|1\n```\n\n**Example:**\n```ini\ncacheex_lg_only_in_aio_only = 1\n```\n\n**Default:**\n```ini\ncacheex_lg_only_in_aio_only = 0\n```", .status = 0 }, - { .param = "cacheex_localgenerated_only_in", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nAccept only CWs which are flagged as localgenerated for incoming CacheEx traffic. This is the global enable/disable switch for the incoming localgenerated-only filter. Works in conjunction with `cacheex_localgenerated_only_in_caid` (deprecated) or `cacheex_lg_only_in_tab`. Here in oscam.conf, the default value is set; user/reader-settings are prioritized.\n\n```ini\ncacheex_localgenerated_only_in = 0 # accept all CWs (default)\ncacheex_localgenerated_only_in = 1 # accept only lg-flagged CWs\n```\n\n**Format:**\n```ini\ncacheex_localgenerated_only_in = 0|1\n```\n\n**Example:**\n```ini\ncacheex_localgenerated_only_in = 1\n```\n\n**Default:**\n```ini\ncacheex_localgenerated_only_in = 0\n```", .status = 0 }, - { .param = "cacheex_localgenerated_only_in_caid", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nCAID table for incoming localgenerated-only filter. Accept only locally generated CWs for these CAIDs. Deprecated: use `cacheex_lg_only_in_tab` instead.\n\n**Format:**\n```ini\ncacheex_localgenerated_only_in_caid = CAID1[,CAID2]...\n```\n\n**Example:**\n```ini\ncacheex_localgenerated_only_in_caid = 0100,0500,1702\n```\n\n**Default:**\n```ini\ncacheex_localgenerated_only_in_caid =\n```", .status = 0 }, - { .param = "cacheex_lg_only_in_tab", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nAllow incoming CWs only if they are lg-flagged for these list of caid/provid(s). Here in oscam.conf, the default value is set; user/reader-settings are prioritized.\n\nIf provid `FFFFFE` is set, all provids for this caid are valid!\n\n**Format:**\n```ini\ncacheex_lg_only_in_tab = caid1:provid1[,provid2];caid2:provid1;\n```", .status = 0 }, - { .param = "cacheex_ecm_filter", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nSet a global cacheex_ecm_filter. Here in oscam.conf, the default value is set; user/reader-settings are prioritized.\n\n**Format:**\n```ini\ncacheex_ecm_filter = [caid][&mask][@provid][$servid],n\n```", .status = 0 }, - { .param = "cacheex_ecm_filter_aio", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nSet a global cacheex_ecm_filter which is used if peer is detected as cx-aio-patched or svn >= 11588. The default limit of 15/30 (camd3/cccam) filters is obsolete.\n\nHere in oscam.conf, the default value is set; user/reader-settings (cacheex_ecm_filter) are prioritized.\n\n**Format:**\n```ini\ncacheex_ecm_filter_aio = [caid][&mask][@provid][$servid],n\n```", .status = 0 }, - { .param = "csp_port", .config = "conf", .section = "cache", .text = "**🔴 Required parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\nThis is a UDP (**not TCP**) listen port for incoming traffic from CSP nodes.\n\n**Example:**\n```ini\ncsp_port = 12345\n```\n\n**Default:**\n```ini\ncsp_port = # none\n```", .status = 0 }, - { .param = "csp_serverip", .config = "conf", .section = "cache", .text = "**🔴 Required parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\nThis is the local bind IP of csp_port.\n\n**Example:**\n```ini\ncsp_serverip = 192.168.1.1\n```\n\n**Default:**\n```ini\ncsp_serverip = # none\n```", .status = 0 }, - { .param = "csp_ecm_filter", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\n**Format:**\n```ini\ncsp_ecm_filter = [caid][&mask][@provid][$servid]\n```", .status = 0 }, - { .param = "csp_allow_request", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\n```ini\ncsp_allow_request = 0\ncsp_allow_request = 1 # default\n```\n\n**Format:**\n```ini\ncsp_allow_request = 0|1\n```\n\n**Example:**\n```ini\ncsp_allow_request = 0\n```\n\n**Default:**\n```ini\ncsp_allow_request = 1\n```", .status = 0 }, - { .param = "csp_allow_reforward", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\nAllow reforwarding of CacheEx CWs via CSP (Cardservproxy protocol).\n\n**Format:**\n```ini\ncsp_allow_reforward = 0|1\n```\n\n**Example:**\n```ini\ncsp_allow_reforward = 1\n```\n\n**Default:**\n```ini\ncsp_allow_reforward = 0\n```", .status = 0 }, - { .param = "cacheex_cw_check", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\n**Format:**\n```ini\ncacheex_cw_check = caid[&mask][@provid][$servid]:mode:counter[,n]\n```\n\n**Mode:**\n\nSpecify behaviour for counter parameter:\n- `0` = when wait_time expires, serve highest counter's CW got anyway, even if no counter reached (default)\n- `1` = never serve CW (coming from cacheex) stored in cache if its counter not reaches counter. When wait_time expires, requests will go to normal readers! Only when a CW reaches counter, it can be served to clients.\n\n**Counter:**\n\nSet minimum CW counter to allow CW is used.\n\n**Default:** `1` (use default behaviour: use CW with highest counter when cache is checked)", .status = 0 }, - { .param = "wait_until_ctimeout", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\nAnswer when cache exchange timeout expires, if no normal readers are available for sending ECMs.\n\n```ini\nwait_until_ctimeout = 0 # immediately send not found to client (default)\nwait_until_ctimeout = 1 # wait for cache exchange answer until client timeout expires\n```\n\n**Format:**\n```ini\nwait_until_ctimeout = 0|1\n```\n\n**Example:**\n```ini\nwait_until_ctimeout = 1\n```\n\n**Default:**\n```ini\nwait_until_ctimeout = 0\n```", .status = 0 }, - { .param = "csp_block_fakecws", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX` compilation flag)**\n\nBlock fake CWs received via CSP. Fake CWs are control words that match patterns defined in oscam.fakecws.\n\n**Format:**\n```ini\ncsp_block_fakecws = 0|1\n```\n\n**Example:**\n```ini\ncsp_block_fakecws = 1\n```\n\n**Default:**\n```ini\ncsp_block_fakecws = 0\n```", .status = 0 }, - { .param = "cacheex_nopushafter", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nDon't forward CWs from local/proxy-reader via CacheEx, if the defined time_in_ms for the CAID is reached. Here in oscam.conf this setting is for evaluating the response-time for local/proxy-readers and is used for CacheEx2-reader/CacheEx3-user as default, when no reader/user cacheex_nopushafter is set.\n\n**Format:**\n```ini\ncacheex_nopushafter = CAID:time_in_ms[,n]\n```", .status = 0 }, - { .param = "waittime_block_start", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nNumber of (dyn)wait_time timeouts to start blocking the use of (dyn)wait_time for this service (caid:provid:srvid).\n\n**Default:**\n```ini\nwaittime_block_start = 0\n```", .status = 0 }, - { .param = "waittime_block_time", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CS_CACHEEX_AIO` compilation flag)**\n\nSeconds the (dyn)wait_time isn't used and ECMs are forwarded to the reader/s.\n\n**Default:**\n```ini\nwaittime_block_time = 0\n```", .status = 0 }, - { .param = "cwcycle_check_enable", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CW_CYCLE_CHECK` compilation flag)**\n\nEnable CW cycle check.\n\n```ini\ncwcycle_check_enable = 0 # disable (default)\ncwcycle_check_enable = 1 # enable\n```\n\n**Format:**\n```ini\ncwcycle_check_enable = 0|1\n```\n\n**Example:**\n```ini\ncwcycle_check_enable = 1\n```\n\n**Default:**\n```ini\ncwcycle_check_enable = 0\n```", .status = 0 }, - { .param = "cwcycle_check_caid", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CW_CYCLE_CHECK` compilation flag)**\n\n⚠️ **Attention: not for all NDS SCs!**\n\nCAID enabled for CW cycle check.\n\n**Format:**\n```ini\ncwcycle_check_caid = CAID[,CAID]...\n```\n\n**Default:** none", .status = 0 }, - { .param = "cwcycle_maxlist", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CW_CYCLE_CHECK` compilation flag)**\n\nMaximum CW cycle list entries.\n\n**Format:**\n```ini\ncwcycle_maxlist = count\n```\n\n**Default:**\n```ini\ncwcycle_maxlist = 500 # maximum = 4000\n```", .status = 0 }, - { .param = "cwcycle_keeptime", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CW_CYCLE_CHECK` compilation flag)**\n\nMinimum time a learned cycletime resists in memory (minutes).\n\n**Default:**\n```ini\ncwcycle_keeptime = 0 # maximum = 15\n```", .status = 0 }, - { .param = "cwcycle_onbad", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CW_CYCLE_CHECK` compilation flag)**\n\n```ini\ncwcycle_onbad = 0 # log bad CW cycle only\ncwcycle_onbad = 1 # drop bad CW cycle (default)\n```\n\n**Format:**\n```ini\ncwcycle_onbad = 0|1\n```\n\n**Example:**\n```ini\ncwcycle_onbad = 0\n```\n\n**Default:**\n```ini\ncwcycle_onbad = 1\n```", .status = 0 }, - { .param = "cwcycle_dropold", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CW_CYCLE_CHECK` compilation flag)**\n\n```ini\ncwcycle_dropold = 0 # no drop (default)\ncwcycle_dropold = 1 # drop old CW cycle\n```\n\n**Format:**\n```ini\ncwcycle_dropold = 0|1\n```\n\n**Example:**\n```ini\ncwcycle_dropold = 1\n```\n\n**Default:**\n```ini\ncwcycle_dropold = 0\n```", .status = 0 }, - { .param = "cwcycle_sensitive", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CW_CYCLE_CHECK` compilation flag)**\n\n```ini\ncwcycle_sensitive = 0 # disabled (default)\ncwcycle_sensitive = 2 # 2 (or more) same bytes and drop new CW\ncwcycle_sensitive = 3 # 3 (or more) same bytes and drop new CW\ncwcycle_sensitive = 4 # 4 (or more) same bytes and drop new CW\n```\n\n**Format:**\n```ini\ncwcycle_sensitive = 0|2|3|4\n```\n\n**Example:**\n```ini\ncwcycle_sensitive = 3\n```\n\n**Default:**\n```ini\ncwcycle_sensitive = 0\n```", .status = 0 }, - { .param = "cwcycle_allowbadfromffb", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CW_CYCLE_CHECK` compilation flag)**\n\nAllow bad cycles from a fixed fallback reader.\n\n```ini\ncwcycle_allowbadfromffb = 0 # default\ncwcycle_allowbadfromffb = 1 # allow bad cycles from fixed fallback reader\n```\n\n**Format:**\n```ini\ncwcycle_allowbadfromffb = 0|1\n```\n\n**Example:**\n```ini\ncwcycle_allowbadfromffb = 1\n```\n\n**Default:**\n```ini\ncwcycle_allowbadfromffb = 0\n```", .status = 0 }, - { .param = "cwcycle_usecwcfromce", .config = "conf", .section = "cache", .text = "**🟢 Optional parameter**\n\n**(requires `CW_CYCLE_CHECK` compilation flag)**\n\nUse CW info from cache exchange.\n\n```ini\ncwcycle_usecwcfromce = 0 # default\ncwcycle_usecwcfromce = 1 # use CW info from cache exchange\n```\n\n**Format:**\n```ini\ncwcycle_usecwcfromce = 0|1\n```\n\n**Example:**\n```ini\ncwcycle_usecwcfromce = 1\n```\n\n**Default:**\n```ini\ncwcycle_usecwcfromce = 0\n```", .status = 0 }, - { .param = "port", .config = "conf", .section = "newcamd", .text = "**🔴 Required parameter**\n\n**(requires `MODULE_NEWCAMD` compilation flag)**\n\nTCP port/DES key/CAID/ident definitions. Each CAID requires a separate port. If you don't specify a DES key for a port, the default DES Key will be used!\n\n**Format:**\n```ini\nport = port[{DES key}]@CAID[:ident][,ident]...[;port[{DES key}]@CAID[:ident][,ident]...]...\n```\n\n**Example:**\n```ini\nport = 15000@1234:000000\n# CAID 1234 connected with port 15000\n\nport = 15000@1234:000000;15001@5678:000000\n# CAID 1234 connected with port 15000, CAID 5678 with port 15001\n```", .status = 0 }, - { .param = "serverip", .config = "conf", .section = "newcamd", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_NEWCAMD` compilation flag)**\n\nBind service to specified IP address.\n\n**Example:**\n```ini\nserverip = 192.168.178.1\n```\n\n**Default:**\n```ini\nserverip =\n```", .status = 0 }, - { .param = "key", .config = "conf", .section = "newcamd", .text = "**🔴 Required parameter**\n\n**(requires `MODULE_NEWCAMD` compilation flag)**\n\nDES key - Default key for newcamd client encryption.\n\n**Example:**\n```ini\nkey = 0102030405060708091011121314\n```", .status = 0 }, - { .param = "keepalive", .config = "conf", .section = "newcamd", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_NEWCAMD` compilation flag)**\n\nEnable keepalive.\n\n```ini\nkeepalive = 0 # disabled (default)\nkeepalive = 1 # enabled\n```\n\n**Format:**\n```ini\nkeepalive = 0|1\n```\n\n**Example:**\n```ini\nkeepalive = 1\n```\n\n**Default:**\n```ini\nkeepalive = 0\n```", .status = 0 }, - { .param = "mgclient", .config = "conf", .section = "newcamd", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_NEWCAMD` compilation flag)**\n\nEnable mgcamd extended newcamd protocol, allowing for a single connection to work with multiple providers.\n\n```ini\nmgclient = 0 # disabled (default)\nmgclient = 1 # enabled\n```\n\n**Format:**\n```ini\nmgclient = 0|1\n```\n\n**Example:**\n```ini\nmgclient = 1\n```\n\n**Default:**\n```ini\nmgclient = 0\n```", .status = 0 }, - { .param = "port", .config = "conf", .section = "cccam", .text = "**🔴 Required parameter**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nTCP/IP-Ports for CCcam clients, enables CCcam protocol!\n\n**Format:**\n```ini\nport = 0|port[,port...]\n```\n\n**Example:**\n```ini\nport = 12000\nport = 12000,12001\nport = 0 # CCcam protocol disabled (default)\n```", .status = 0 }, - { .param = "serverip", .config = "conf", .section = "cccam", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nBind service to specified IP address.\n\n**Example:**\n```ini\nserverip = 192.168.178.1\n```\n\n**Default:**\n```ini\nserverip =\n```", .status = 0 }, - { .param = "nodeid", .config = "conf", .section = "cccam", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nSet CCcam node ID in hex.\n\n**Format:**\n```ini\nnodeid = ID\n```\n\n**Example:**\n```ini\nnodeid = 0a0b0c0d0e0f1011\n```\n\n**Default:** none", .status = 0 }, - { .param = "version", .config = "conf", .section = "cccam", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nDefine CCcam version, minimum CCcam version 2.0.11, used with original CCcam only.\n\n**Format:**\n```ini\nversion =
    ,,\n```\n\n**Example:**\n```ini\nversion = 2.0.11\n```\n\n**Default:** none", .status = 0 }, - { .param = "reshare", .config = "conf", .section = "cccam", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nReshare level for CCcam clients.\n\n**Format:**\n```ini\nreshare = -1 # no resharing\nreshare = 0 # resharing for direct peer only\nreshare = 1 # resharing for direct peer and next level\nreshare = x # resharing for direct peer and next x level (x for number of level)\nreshare = 10 # default\n```\n\n**Example:**\n```ini\nreshare = 1\n```\n\n**Default:**\n```ini\nreshare = 10\n```\n\nReshare could be defined in 2 ways:\n- reader (`cccreshare`)\n- user-account (`cccreshare`)\n\nA card's reshare value is set to the smallest value of the 2 parameters!", .status = 0 }, - { .param = "reshare_mode", .config = "conf", .section = "cccam", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nCCcam reshare mode.\n\n**Format:**\n```ini\nreshare_mode = 0 # reader reshares only received SCs for CCcam readers,\n # defined filters/CAIDs/idents on other readers (default)\nreshare_mode = 1 # reader reshares received SCs (like=0) and defined services\nreshare_mode = 2 # reader reshares only defined reader services as virtual SCs\nreshare_mode = 3 # reader reshares only defined user services as virtual SCs\nreshare_mode = 4 # reader reshares only received cards\n```\n\n**Example:**\n```ini\nreshare_mode = 1\n```\n\n**Default:**\n```ini\nreshare_mode = 0\n```\n\nEvery server is shared as hop=0 and with defined reshare values.\n\nService reshare only works if positive services defined: no service - no reshare!", .status = 0 }, - { .param = "ignorereshare", .config = "conf", .section = "cccam", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nCCcam reshare setting.\n\n```ini\nignorereshare = 0 # use reshare setting of server (default)\nignorereshare = 1 # use reshare setting of reader or user\n```\n\n**Format:**\n```ini\nignorereshare = 0|1\n```\n\n**Example:**\n```ini\nignorereshare = 1\n```\n\n**Default:**\n```ini\nignorereshare = 0\n```", .status = 0 }, - { .param = "forward_origin_card", .config = "conf", .section = "cccam", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nForward ECM request to reader holding this card, loadbalancer, fallback and caching will be disabled.\n\n```ini\nforward_origin_card = 0 # default\nforward_origin_card = 1 # forward ECM request to reader holding this card\n```\n\n**Format:**\n```ini\nforward_origin_card = 0|1\n```\n\n**Example:**\n```ini\nforward_origin_card = 1\n```\n\n**Default:**\n```ini\nforward_origin_card = 0\n```", .status = 0 }, - { .param = "stealth", .config = "conf", .section = "cccam", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nBehaviour like the original CCcam: no activate partner detection and extended OSCam-CCcam protocol, prevent other OSCam to detect the server as OSCam server.\n\n```ini\nstealth = 0 # stealth disabled (default)\nstealth = 1 # stealth enabled\n```\n\n**Format:**\n```ini\nstealth = 0|1\n```\n\n**Example:**\n```ini\nstealth = 1\n```\n\n**Default:**\n```ini\nstealth = 0\n```", .status = 0 }, - { .param = "updateinterval", .config = "conf", .section = "cccam", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nInterval to provide share list update to CCcam clients in seconds.\n\n**Format:**\n```ini\nupdateinterval = 0 # update based on server updates, values <= 10 are invalid and will be set to 30\nupdateinterval = 240 # default\n```\n\n**Example:**\n```ini\nupdateinterval = 120\n```\n\n**Default:**\n```ini\nupdateinterval = 240\n```", .status = 0 }, - { .param = "minimizecards", .config = "conf", .section = "cccam", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nMode how to provide CCcam servers to CCcam clients.\n\n```ini\nminimizecards = 0 # no aggregation, remove duplicates only (default)\nminimizecards = 1 # based on minimum hop: two SCs with different hops are summarized,\n # new SCs get a smaller hop\n```\n\n**Format:**\n```ini\nminimizecards = 0|1\n```\n\n**Example:**\n```ini\nminimizecards = 1\n```\n\n**Default:**\n```ini\nminimizecards = 0\n```", .status = 0 }, - { .param = "keepconnected", .config = "conf", .section = "cccam", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nSet CCcam keepalive mode.\n\n```ini\nkeepconnected = 0 # disconnect client when max idle time is reached\nkeepconnected = 1 # keep client connected (default)\n```\n\n**Format:**\n```ini\nkeepconnected = 0|1\n```\n\n**Example:**\n```ini\nkeepconnected = 0\n```\n\n**Default:**\n```ini\nkeepconnected = 1\n```", .status = 0 }, - { .param = "recv_timeout", .config = "conf", .section = "cccam", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CCCAM` compilation flag)**\n\nSet network timeout for receiving data.\n\n**Format:**\n```ini\nrecv_timeout = milliseconds\n```\n\n**Default:**\n```ini\nrecv_timeout = 2000\n```", .status = 0 }, - { .param = "port", .config = "conf", .section = "camd33", .text = "**🔴 Required parameter**\n\n**(requires `MODULE_CAMD33` compilation flag)**\n\nTCP/IP port for camd 3.3x clients.\n\n**Example:**\n```ini\nport = 15000\nport = 0 # disabled (default)\n```", .status = 0 }, - { .param = "serverip", .config = "conf", .section = "camd33", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CAMD33` compilation flag)**\n\nBind service to specified IP address.\n\n**Example:**\n```ini\nserverip = 192.168.178.1\n```\n\n**Default:**\n```ini\nserverip = # listening to all\n```", .status = 0 }, - { .param = "nocrypt", .config = "conf", .section = "camd33", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CAMD33` compilation flag)**\n\nUnsecured camd 3.3x client connection.\n\n**Format:**\n```ini\nnocrypt = IP address|IP address range[,IP address|IP address range]...\n```\n\n**Example:**\n```ini\nnocrypt = 127.0.0.1,192.168.0.0-192.168.255.255\n```\n\n**Default:**\n```ini\nnocrypt = # none\n```", .status = 0 }, - { .param = "passive", .config = "conf", .section = "camd33", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CAMD33` compilation flag)**\n\nForce passive camd 3.3x client.\n\nCamd3.3x protocol generally has active clients. In certain circumstances the client must be switched to \"passive\" mode only.\n\n**Example:**\n```ini\npassive = 1\n```\n\n**Default:**\n```ini\npassive = 0\n```", .status = 0 }, - { .param = "key", .config = "conf", .section = "camd33", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CAMD33` compilation flag)**\n\n128 bit key for camd 3.3x client encryption.\n\n**Example:**\n```ini\nkey = 01020304050607080910111213141516\n```\n\n**Default:**\n```ini\nkey = # none\n```", .status = 0 }, - { .param = "port", .config = "conf", .section = "cs357x", .text = "**🔴 Required parameter**\n\n**(requires `MODULE_CAMD35` compilation flag)**\n\nUDP port for camd 3.5x|cs357x clients. Port must be opened at router!\n\n**Example:**\n```ini\nport = 15000\nport = 0 # disabled (default)\n```", .status = 0 }, - { .param = "serverip", .config = "conf", .section = "cs357x", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CAMD35` compilation flag)**\n\nBind service to specified IP address.\n\n**Example:**\n```ini\nserverip = 192.168.178.1\n```\n\n**Default:**\n```ini\nserverip = # all (default)\n```", .status = 0 }, - { .param = "suppresscmd08", .config = "conf", .section = "cs357x", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CAMD35` compilation flag)**\n\nTell camd35|cs3.57x-clients not to request again for rejected CAID, service ID and provider ID combination.\n\n```ini\nsuppresscmd08 = 0 # enabled (default)\nsuppresscmd08 = 1 # disabled\n```\n\n**Format:**\n```ini\nsuppresscmd08 = 0|1\n```\n\n**Example:**\n```ini\nsuppresscmd08 = 1\n```\n\n**Default:**\n```ini\nsuppresscmd08 = 0\n```\n\nCan be overwritten in oscam.user!\n\nMore information: [Streamboard-Thread](http://www.streamboard.tv/wbb2/thread.php?threadid=27459)", .status = 0 }, - { .param = "port", .config = "conf", .section = "cs378x", .text = "**🔴 Required parameter**\n\n**(requires `MODULE_CAMD35_TCP` compilation flag)**\n\nPort(s) TCP for cs378x clients (camd 3.5x in TCP mode). Port(s) must be opened at router!\n\n**Format:**\n```ini\nport = port@CAID[:ident][,ident]...[;port@CAID[:ident][,ident]...]...\n```\n\n**Example:**\n```ini\nport = 15000@0500:030B00;22764@0648\n```", .status = 0 }, - { .param = "serverip", .config = "conf", .section = "cs378x", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CAMD35_TCP` compilation flag)**\n\nBind service to specified IP address.\n\n**Example:**\n```ini\nserverip = 192.168.178.1\n```\n\n**Default:**\n```ini\nserverip = # all (default)\n```", .status = 0 }, - { .param = "suppresscmd08", .config = "conf", .section = "cs378x", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_CAMD35_TCP` compilation flag)**\n\nTell cs3.78x clients not to request again for rejected CAID, service ID and provider ID combination.\n\n```ini\nsuppresscmd08 = 0 # enabled (default)\nsuppresscmd08 = 1 # disabled\n```\n\n**Format:**\n```ini\nsuppresscmd08 = 0|1\n```\n\n**Example:**\n```ini\nsuppresscmd08 = 1\n```\n\n**Default:**\n```ini\nsuppresscmd08 = 0\n```\n\nMore information: [Streamboard-Thread](http://www.streamboard.tv/wbb2/thread.php?threadid=27459)", .status = 0 }, - { .param = "port", .config = "conf", .section = "radegast", .text = "**🔴 Required parameter**\n\n**(requires `MODULE_RADEGAST` compilation flag)**\n\nTCP/IP port for radegast clients (enables radegast).\n\n**Example:**\n```ini\nport = 15000\n```\n\n**Default:**\n```ini\nport = 0\n```", .status = 0 }, - { .param = "serverip", .config = "conf", .section = "radegast", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_RADEGAST` compilation flag)**\n\nBind service to specified IP address.\n\n**Example:**\n```ini\nserverip = 192.162.9.1\n```\n\n**Default:**\n```ini\nserverip = # all IPs allowed (default)\n```", .status = 0 }, - { .param = "allowed", .config = "conf", .section = "radegast", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_RADEGAST` compilation flag)**\n\nClient connections allowed from.\n\n**Format:**\n```ini\nallowed = IP address|IP range[,IP address|IP range]...\n```\n\n**Example:**\n```ini\nallowed = 127.0.0.1,192.168.0.0-192.168.255.255\n# Host and range 192.168.0 are allowed\n```", .status = 0 }, - { .param = "user", .config = "conf", .section = "radegast", .text = "**🔴 Required parameter**\n\n**(requires `MODULE_RADEGAST` compilation flag)**\n\nUser name for radegast client.\n\n**Format:**\n```ini\nuser = username\n```", .status = 0 }, - { .param = "Minimal", .config = "conf", .section = "gbox", .text = "Let's say the gbox runs on host 192.168.1.101 and OSCam is on 192.168.1.123. In file **cwshare.cfg** on gbox side we have, for example, the following lines:\n\n```\nM: { 192.168.1.101 { A123BCDE }}\nD: { 192.168.1.123 { 3820 3819 { 98AF3E25 {3 3}}}}\n```\n\nIf oscam_gbox should connect to the original GBOX above, then you should configure OSCam as follows:\n\n**oscam.conf:**\n```ini\n[gbox]\nhostname = 192.168.1.123\nmy_password = 98AF3E25\nport = 3819\n```\n\n**oscam.server:**\n```ini\n[reader]\nprotocol = gbox\ngroup = 1\ndevice = 192.168.1.101,3820\npassword = A123BCDE\nuser = gbox_client_1\n```\n\n**oscam.user:**\n```ini\n[account]\nuser = gbox_client_1\ngroup = 1\n```", .status = 0 }, - { .param = "port", .config = "conf", .section = "gbox", .text = "**🔴 Required parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nDefine incoming UDP port(s) used by Gbox protocol.\n\n**Format:**\n```ini\nport = port#1[[,port#2]...[,port#32]]\n```\n\nMaximum 32 ports.", .status = 0 }, - { .param = "hostname", .config = "conf", .section = "gbox", .text = "**🔴 Required parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nMy IP or DDNS.\n\n**Examples:**\n```ini\nhostname = 192.168.1.120\nhostname = willy.noip.org\n```", .status = 0 }, - { .param = "my_password", .config = "conf", .section = "gbox", .text = "**🔴 Required parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\n4 hex bytes, 8 characters.\n\n**Example:**\n```ini\nmy_password = 98AF3E25\n```", .status = 0 }, - { .param = "myid", .config = "conf", .section = "gbox", .text = "**ℹ️ Display only**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nThis is **not a configurable parameter**. The GBox ID (`myid`) is automatically calculated from `my_password` and displayed in the WebIF for informational purposes only.\n\nThe GBox ID is a 2-byte (4 hex character) identifier derived from the 4-byte password using a conversion algorithm. It uniquely identifies your GBox peer in the network.\n\n**Display in WebIF:**\n- Location: Configuration → GBox → \"My Id\"\n- Format: 4 hex characters (e.g., `3E25`)\n- Read-only: Cannot be modified directly\n\n**Note:** To change your GBox ID, you must change `my_password`. The ID will be recalculated automatically.", .status = 0 }, - { .param = "gbox_reconnect", .config = "conf", .section = "gbox", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nSend hello message to peers in seconds (min: 60, max: 300).\n\n**Format:**\n```ini\ngbox_reconnect = 60-300\n```\n\n**Example:**\n```ini\ngbox_reconnect = 120\n```\n\n**Default:**\n```ini\ngbox_reconnect = 180\n```", .status = 0 }, - { .param = "my_vers", .config = "conf", .section = "gbox", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nSet gbox version hexadecimal low byte.\n\n**Format:**\n```ini\nmy_vers = hex_byte\n```\n\n**Example:**\n```ini\nmy_vers = 30\n```\n\n**Default:**\n```ini\nmy_vers = 2A\n```", .status = 0 }, - { .param = "my_cpu_api", .config = "conf", .section = "gbox", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nSet gbox CPU and API byte in hexadecimal.\n\n**Format:**\n```ini\nmy_cpu_api = hex_byte\n```\n\n**Example:**\n```ini\nmy_cpu_api = 40\n```\n\n**Default:**\n```ini\nmy_cpu_api = 61\n```", .status = 0 }, - { .param = "gsms_disable", .config = "conf", .section = "gbox", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nDisable Gbox Short Message Service (GSMS).\n\n```ini\ngsms_disable = 0 # GSMS is enabled\ngsms_disable = 1 # disable GSMS (default)\n```\n\n**Format:**\n```ini\ngsms_disable = 0|1\n```\n\n**Example:**\n```ini\ngsms_disable = 0\n```\n\n**Default:**\n```ini\ngsms_disable = 1\n```", .status = 0 }, - { .param = "gbox_save_gsms", .config = "conf", .section = "gbox", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nSave GSMS in configuration.\n\n```ini\ngbox_save_gsms = 0 # don't save GSMS in configuration\ngbox_save_gsms = 1 # save all GSMS field in configuration\n```\n\n⚠️ **Note:** You need to press save button to really save it!", .status = 0 }, - { .param = "dis_attack_txt", .config = "conf", .section = "gbox", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nDisable creation of attack.txt.\n\n```ini\ndis_attack_txt = 0 # default\ndis_attack_txt = 1 # disable\n```\n\n**Format:**\n```ini\ndis_attack_txt = 0|1\n```\n\n**Example:**\n```ini\ndis_attack_txt = 1\n```\n\n**Default:**\n```ini\ndis_attack_txt = 0\n```", .status = 0 }, - { .param = "log_hello", .config = "conf", .section = "gbox", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nDisplay hello messages in debug log.\n\n```ini\nlog_hello = 0\nlog_hello = 1 # default\n```\n\n**Format:**\n```ini\nlog_hello = 0|1\n```\n\n**Example:**\n```ini\nlog_hello = 0\n```\n\n**Default:**\n```ini\nlog_hello = 1\n```", .status = 0 }, - { .param = "tmp_dir", .config = "conf", .section = "gbox", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nGbox temporary directory.\n\n**Format:**\n```ini\ntmp_dir = path\n```\n\n**Example:**\n```ini\ntmp_dir = /var/gbox\n```\n\n**Default:**\n```ini\ntmp_dir = /tmp/.oscam\n```", .status = 0 }, - { .param = "ignore_peer", .config = "conf", .section = "gbox", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nIgnore specific peer ID(s).\n\n**Format:**\n```ini\nignore_peer = peer#1[[,peer#2]...[,peer#16]]\n```\n\nRules:\n- If peer = dist 1 → Login of peer rejected\n- If peer > dist 1 → card(s) of peer ignored", .status = 0 }, - { .param = "accept_remm_peer", .config = "conf", .section = "gbox", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nAccept to send Remote EMMs to specified Server Peer-IDs.\n\n**Format:**\n```ini\naccept_remm_peer = peer#1[[,peer#2]...[,peer#8]]\n```", .status = 0 }, - { .param = "block_ecm", .config = "conf", .section = "gbox", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nBlock ECM for specific peer ID(s).\n\n**Format:**\n```ini\nblock_ecm = peer#1[[,peer#2]...[,peer#16]]\n```", .status = 0 }, - { .param = "proxy_card", .config = "conf", .section = "gbox", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nProxy reader card(s) to be reshared into gbox network.\n\n**Format:**\n```ini\nproxy_card = [,]...\n```\n\n**Example:**\n```ini\nproxy_card = 18300000,0D950400,05050F00\n```\n\n**Default:** none", .status = 0 }, - { .param = "gbox_save_gsms", .config = "conf", .section = "gbox", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nSave GSMS in configuration.\n\n```ini\ngbox_save_gsms = 0 # don't save GSMS in configuration\ngbox_save_gsms = 1 # save all GSMS field in configuration\n```\n\n⚠️ **Note:** You need to press save button to really save it!", .status = 0 }, - { .param = "gbox_msg_type", .config = "conf", .section = "gbox", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nSet GSMS message type.\n\n**Format:**\n```ini\ngbox_msg_type = 0 # normal text message (default)\ngbox_msg_type = 1 # normal text message + OSD (On Screen Display)\n```\n\n**Example:**\n```ini\ngbox_msg_type = 1\n```\n\n**Default:**\n```ini\ngbox_msg_type = 0\n```", .status = 0 }, - { .param = "gbox_dest_peers", .config = "conf", .section = "gbox", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nDestination peers for GSMS.\n\n**Format:**\n```ini\ngbox_dest_peers = [BOXID[,BOXID]...[,BOXID]]\n```\n\nMaximum 16 * 2 bytes (4 hexa digits), comma-separated. For broadcast to all use FFFF.", .status = 0 }, - { .param = "gbox_msg_txt", .config = "conf", .section = "gbox", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nText to send to peers via GSMS.\n\n**Format:**\n```ini\ngbox_msg_txt = Your text to send to peers.\n```\n\nFrom 6 to 127 alphanumerical characters.", .status = 0 }, - { .param = "ccc_reshare", .config = "conf", .section = "gbox", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_GBOX` compilation flag)**\n\nEnable CCcam-cards to be reshared into gbox network (global setting).\n\n```ini\nccc_reshare = 0 # default\nccc_reshare = 1 # enable CCcam-cards reshare\n```\n\n**Format:**\n```ini\nccc_reshare = 0|1\n```\n\n**Example:**\n```ini\nccc_reshare = 1\n```\n\n**Default:**\n```ini\nccc_reshare = 0\n```\n\n⚠️ **Attention:** Peer specific reshare level to be set in oscam.server [reader] → cccam_reshare\n\n⚠️ **Attention:** Peer specific ident filter can be set in oscam.server [reader] → ccc_gbx_reshare_ident", .status = 0 }, - { .param = "Minimal", .config = "conf", .section = "streamrelay", .text = "The following example shows a basic Streamrelay setup where OSCam connects to a local Enigma2 receiver as stream source:\n\n```ini\n[streamrelay]\nstream_relay_enabled = 1\nstream_relay_port = 17999\nstream_relay_user = streamuser\nstream_source_host = 192.168.1.100\nstream_source_port = 8001\n```\n\nIn this setup:\n- OSCam listens on port 17999 for incoming client connections\n- The stream source is an Enigma2 box at 192.168.1.100:8001\n- The user `streamuser` must be defined in oscam.user\n\nClients can then connect to: `http://oscam-ip:17999/caid:srvid`", .status = 0 }, - { .param = "stream_relay_enabled", .config = "conf", .section = "streamrelay", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_STREAMRELAY` compilation flag)**\n\nEnable or disable the Streamrelay server.\n\n```ini\nstream_relay_enabled = 0 # disabled (default)\nstream_relay_enabled = 1 # enabled\n```\n\n**Format:**\n```ini\nstream_relay_enabled = 0|1\n```\n\n**Example:**\n```ini\nstream_relay_enabled = 1\n```\n\n**Default:**\n```ini\nstream_relay_enabled = 0\n```", .status = 0 }, - { .param = "stream_relay_port", .config = "conf", .section = "streamrelay", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_STREAMRELAY` compilation flag)**\n\nTCP port on which the Streamrelay server listens for incoming client connections.\n\n**Example:**\n```ini\nstream_relay_port = 17999\n```\n\n**Default:**\n```ini\nstream_relay_port = 17999\n```", .status = 0 }, - { .param = "stream_relay_user", .config = "conf", .section = "streamrelay", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_STREAMRELAY` compilation flag)**\n\nUsername for the Streamrelay client. This user must be defined in oscam.user with appropriate permissions. If not set, the first valid user account will be used.\n\n**Example:**\n```ini\nstream_relay_user = streamclient\n```\n\n**Default:** none (uses first available user)", .status = 0 }, - { .param = "stream_relay_ctab", .config = "conf", .section = "streamrelay", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_STREAMRELAY` compilation flag)**\n\nCAID table to restrict which CAIDs are handled by Streamrelay. Only streams with matching CAIDs will be descrambled.\n\n**Format:**\n```ini\nstream_relay_ctab = CAID1[,CAID2]...\n```\n\n**Example:**\n```ini\nstream_relay_ctab = 0963,098D,09CD\n```\n\n**Default:** none (CAIDs are detected automatically)", .status = 0 }, - { .param = "stream_source_host", .config = "conf", .section = "streamrelay", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_STREAMRELAY` compilation flag)**\n\nIP address or hostname of the stream source server (e.g., Enigma2 receiver, SAT>IP server, or Tvheadend). This is where OSCam fetches the encrypted stream from.\n\n**Example:**\n```ini\nstream_source_host = 192.168.1.100\nstream_source_host = my-enigma2-box.local\n```\n\n**Default:**\n```ini\nstream_source_host = 127.0.0.1\n```", .status = 0 }, - { .param = "stream_client_source_host", .config = "conf", .section = "streamrelay", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_STREAMRELAY` compilation flag)**\n\nDetermines how the stream source host is resolved for client connections.\n\n```ini\nstream_client_source_host = 0 # always use stream_source_host\nstream_client_source_host = 1 # use source host from client request if available (default)\n```\n\nWhen enabled, OSCam can use the stream source information provided by the connecting client, allowing more flexible multi-source setups.\n\n**Format:**\n```ini\nstream_client_source_host = 0|1\n```\n\n**Example:**\n```ini\nstream_client_source_host = 0\n```\n\n**Default:**\n```ini\nstream_client_source_host = 1\n```", .status = 0 }, - { .param = "stream_source_port", .config = "conf", .section = "streamrelay", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_STREAMRELAY` compilation flag)**\n\nTCP port of the stream source server.\n\n**Example:**\n```ini\nstream_source_port = 8001\n```\n\n**Default:**\n```ini\nstream_source_port = 8001 # for Enigma2-based builds\nstream_source_port = 31339 # for Neutrino-based builds\n```\n\n⚠️ **Note:** The default value depends on the platform OSCam was compiled for.", .status = 0 }, - { .param = "stream_source_auth_user", .config = "conf", .section = "streamrelay", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_STREAMRELAY` compilation flag)**\n\nUsername for HTTP Basic Authentication when connecting to the stream source. Required if the stream source server requires authentication.\n\n**Example:**\n```ini\nstream_source_auth_user = admin\n```\n\n**Default:** none", .status = 0 }, - { .param = "stream_source_auth_password", .config = "conf", .section = "streamrelay", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_STREAMRELAY` compilation flag)**\n\nPassword for HTTP Basic Authentication when connecting to the stream source. Used together with `stream_source_auth_user`.\n\n**Example:**\n```ini\nstream_source_auth_password = secret123\n```\n\n**Default:** none", .status = 0 }, - { .param = "stream_relay_buffer_time", .config = "conf", .section = "streamrelay", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_STREAMRELAY` compilation flag)**\n\nBuffer time in milliseconds before starting to relay the stream. A higher value provides more stable playback but increases latency. Useful when experiencing stream interruptions.\n\n**Format:**\n```ini\nstream_relay_buffer_time = milliseconds\n```\n\n**Example:**\n```ini\nstream_relay_buffer_time = 500 # 500ms buffer\n```\n\n**Default:**\n```ini\nstream_relay_buffer_time = 0 # no additional buffering\n```", .status = 0 }, - { .param = "stream_relay_reconnect_count", .config = "conf", .section = "streamrelay", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_STREAMRELAY` compilation flag)**\n\nNumber of reconnection attempts to the stream source if the connection is lost. After this limit is reached, the stream is terminated.\n\n**Example:**\n```ini\nstream_relay_reconnect_count = 5 # try 5 reconnects\n```\n\n**Default:**\n```ini\nstream_relay_reconnect_count = 0 # no automatic reconnect\n```", .status = 0 }, - { .param = "stream_display_client", .config = "conf", .section = "streamrelay", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_STREAMRELAY` compilation flag)**\n\nDetermines which address is displayed for Streamrelay connections in the status display and WebIF.\n\n```ini\nstream_display_client = 0 # show stream client address (default)\nstream_display_client = 1 # show stream source host address\n```\n\n**Format:**\n```ini\nstream_display_client = 0|1\n```\n\n**Example:**\n```ini\nstream_display_client = 1\n```\n\n**Default:**\n```ini\nstream_display_client = 0\n```", .status = 0 }, - { .param = "stream_reuse_client", .config = "conf", .section = "streamrelay", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_STREAMRELAY` compilation flag)**\n\nReuse existing client connections when the same client reconnects. This can reduce overhead for clients that frequently disconnect and reconnect (e.g., during channel changes).\n\n```ini\nstream_reuse_client = 0 # create new client connection each time (default)\nstream_reuse_client = 1 # reuse existing client connection\n```\n\n**Format:**\n```ini\nstream_reuse_client = 0|1\n```\n\n**Example:**\n```ini\nstream_reuse_client = 1\n```\n\n**Default:**\n```ini\nstream_reuse_client = 0\n```", .status = 0 }, - { .param = "stream_hide_client", .config = "conf", .section = "streamrelay", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_STREAMRELAY` and `WEBIF` compilation flags)**\n\nHide Streamrelay clients from the WebIF status display. Useful to reduce clutter in environments with many stream connections.\n\n```ini\nstream_hide_client = 0 # show clients in WebIF (default)\nstream_hide_client = 1 # hide clients from WebIF\n```\n\n**Format:**\n```ini\nstream_hide_client = 0|1\n```\n\n**Example:**\n```ini\nstream_hide_client = 1\n```\n\n**Default:**\n```ini\nstream_hide_client = 0\n```\n\n⚠️ **Note:** This parameter is only available when OSCam is compiled with WebIF support.", .status = 0 }, - { .param = "enabled", .config = "conf", .section = "dvbapi", .text = "**🟢 Optional parameter**\n\n**(requires `HAVE_DVBAPI` compilation flag)**\n\nDVB API enabled.\n\n```ini\nenabled = 0 # disabled (default)\nenabled = 1 # enabled\n```\n\n**Format:**\n```ini\nenabled = 0|1\n```\n\n**Example:**\n```ini\nenabled = 1\n```\n\n**Default:**\n```ini\nenabled = 0\n```", .status = 0 }, - { .param = "au", .config = "conf", .section = "dvbapi", .text = "**🟢 Optional parameter**\n\n**(requires `HAVE_DVBAPI` compilation flag)**\n\nAU mode for dvbapi.\n\n```ini\nau = 0 # disable AU (default)\nau = 1 # enable AU\n```\n\n**Format:**\n```ini\nau = 0|1\n```\n\n**Example:**\n```ini\nau = 1\n```\n\n**Default:**\n```ini\nau = 0\n```", .status = 0 }, - { .param = "pmt_mode", .config = "conf", .section = "dvbapi", .text = "**🟢 Optional parameter**\n\n**(requires `HAVE_DVBAPI` compilation flag)**\n\nPMT mode.\n\n```ini\npmt_mode = 0 # use camd.socket and PMT file (default)\npmt_mode = 1 # disable reading PMT file\npmt_mode = 2 # disable camd.socket\npmt_mode = 3 # read PMT file on startup only\npmt_mode = 4 # do not use signal handler for monitoring /tmp\npmt_mode = 5 # do not use signal handler to monitor /tmp & disable camd.socket\npmt_mode = 6 # use PMT server mode (NEW svn8680:05/06/2013)\n```\n\n**Format:**\n```ini\npmt_mode = 0|1|2|3|4|5|6\n```\n\n**Example:**\n```ini\npmt_mode = 6\n```\n\n**Default:**\n```ini\npmt_mode = 0\n```", .status = 0 }, - { .param = "request_mode", .config = "conf", .section = "dvbapi", .text = "**🟢 Optional parameter**\n\n**(requires `HAVE_DVBAPI` compilation flag)**\n\nCAID request mode.\n\n```ini\nrequest_mode = 0 # try all possible CAIDs one by one (default)\nrequest_mode = 1 # try all CAIDs simultaneously\n```\n\n**Format:**\n```ini\nrequest_mode = 0|1\n```\n\n**Example:**\n```ini\nrequest_mode = 1\n```\n\n**Default:**\n```ini\nrequest_mode = 0\n```", .status = 0 }, - { .param = "listen_port", .config = "conf", .section = "dvbapi", .text = "**🟢 Optional parameter**\n\n**(requires `HAVE_DVBAPI` compilation flag)**\n\nTCP/IP port for SAT IP clients, filtering has to be done on client site.\n\n**Format:**\n```ini\nlisten_port = port\n```\n\n**Example:**\n```ini\nlisten_port = 9000\n```\n\n**Default:**\n```ini\nlisten_port = 0\n```", .status = 0 }, - { .param = "delayer", .config = "conf", .section = "dvbapi", .text = "**🟢 Optional parameter**\n\n**(requires `HAVE_DVBAPI` compilation flag)**\n\nMinimum time to write CW.\n\n**Format:**\n```ini\ndelayer = milliseconds\n```", .status = 0 }, - { .param = "ecminfo_file", .config = "conf", .section = "dvbapi", .text = "**🟢 Optional parameter**\n\n**(requires `HAVE_DVBAPI` compilation flag)**\n\nEnable or disable writing ecm.info file. The ecm.info file contains information about the current decryption.\n\n**Format:**\n```ini\necminfo_file = 0|1\n```\n\n**Example:**\n```ini\necminfo_file = 1\n```\n\n**Default:**\n```ini\necminfo_file = 1\n```", .status = 0 }, - { .param = "ecminfo_type", .config = "conf", .section = "dvbapi", .text = "**🟢 Optional parameter**\n\n**(requires `HAVE_DVBAPI` compilation flag)**\n\nDefine the type of ecm.info file to create.\n\n**Format:**\n```ini\necminfo_type = 0 # default oscam syntax\necminfo_type = 1 # default oscam syntax with ecmtime in ms instead of s\necminfo_type = 2 # wicardd\necminfo_type = 3 # mgcamd\necminfo_type = 4 # cccam\necminfo_type = 5 # camd3\n```\n\n**Example:**\n```ini\necminfo_type = 3\n```\n\n**Default:**\n```ini\necminfo_type = 0\n```", .status = 0 }, - { .param = "user", .config = "conf", .section = "dvbapi", .text = "**🔴 Required parameter**\n\n**(requires `HAVE_DVBAPI` compilation flag)**\n\nUser name for DVB API client.\n\n**Example:**\n```ini\nuser = user1\n```\n\n**Default:**\n```ini\nuser = # anonymous\n```", .status = 0 }, - { .param = "read_sdt", .config = "conf", .section = "dvbapi", .text = "**🟢 Optional parameter**\n\n**(requires `HAVE_DVBAPI` compilation flag)**\n\nIf it is not yet available, this option automatically adds entries in your oscam.srvid2 (or oscam.srvid) and in your oscam.provid files. You need to stay **more than 30 seconds** on a channel for the auto-detect to start. So both channel name and provider name are retrieved. If entries already exist they are not changed nor updated, so you keep full control on the content of both files, only missing entries are added.\n\n```ini\nread_sdt = 0 # disabled (default)\nread_sdt = 1 # on, do not save FTA channels\nread_sdt = 2 # on, save FTA channels\n```\n\n**Format:**\n```ini\nread_sdt = 0|1|2\n```\n\n**Example:**\n```ini\nread_sdt = 1\n```\n\n**Default:**\n```ini\nread_sdt = 0\n```", .status = 0 }, - { .param = "write_sdt_prov", .config = "conf", .section = "dvbapi", .text = "**🟢 Optional parameter**\n\n**(requires `HAVE_DVBAPI` compilation flag)**\n\nFirst enable the read_sdt parameter then you can specify if the provider name is saved or not into the oscam.srvid2 or oscam.srvid file. This is not mandatory since the provider name is now retrieved automatically from the oscam.provid file.\n\n```ini\nwrite_sdt_prov = 0 # off, do not write provider name into oscam.srvid/2 (default)\nwrite_sdt_prov = 1 # on, write provider name into oscam.srvid/2\n```\n\n**Format:**\n```ini\nwrite_sdt_prov = 0|1\n```\n\n**Example:**\n```ini\nwrite_sdt_prov = 1\n```\n\n**Default:**\n```ini\nwrite_sdt_prov = 0\n```", .status = 0 }, - { .param = "extended_cw_api", .config = "conf", .section = "dvbapi", .text = "**🟢 Optional parameter**\n\n**(requires `WITH_EXTENDED_CW` compilation flag)**\n\nAPI for extended control words.\n\n**Format:**\n```ini\nextended_cw_api = 0 # none / disabled (default)\nextended_cw_api = 1 # OE2.2+ (OpenEmbedded 2.2, 2.5)\nextended_cw_api = 2 # OE2.0 (OpenEmbedded 2.0)\n```\n\n**Example:**\n```ini\nextended_cw_api = 1\n```\n\n**Default:**\n```ini\nextended_cw_api = 0\n```", .status = 0 }, - { .param = "demuxer_fix", .config = "conf", .section = "dvbapi", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_STREAMRELAY` compilation flag)**\n\nFix for demuxer issues related to Stream Relay. Enable this if you experience problems with stream relay and demuxing.\n\n**Format:**\n```ini\ndemuxer_fix = 0|1\n```\n\n**Example:**\n```ini\ndemuxer_fix = 1\n```\n\n**Default:**\n```ini\ndemuxer_fix = 0\n```", .status = 0 }, - { .param = "boxtype", .config = "conf", .section = "dvbapi", .text = "**🔴 Required parameter**\n\n**(requires `HAVE_DVBAPI` compilation flag)**\n\nSet boxtype, auto detection of DVB API will be aspired.\n\n**Format:**\n```ini\nboxtype = dbox2|dreambox|dm7000|duckbox|ufs910|ipbox|ipbox-pmt|qboxhd|coolstream|neumo|pc\n```\n\n**Notes:**\n- `ipbox` with camd.socket support, currently only with PGI image version 0.6 or above, verified on HD models only\n- `ipbox-pmt` can be used on any DGS based images (with or without camd.socket support), verified on HD models only\n- `pc` is for generic pc support (currently supported on VDR with vdr-plugin-dvbapi)\n\n**Default:**\n```ini\nboxtype = dreambox\n```", .status = 0 }, - { .param = "services", .config = "conf", .section = "dvbapi", .text = "**🟢 Optional parameter**\n\n**(requires `HAVE_DVBAPI` compilation flag)**\n\nServices filter for DVBAPI. Define which services (from oscam.services) are allowed or denied for DVBAPI.\n\n**Format:**\n```ini\nservices = [!]services1[,[!]services2]...\n```\n\n**Example:**\n```ini\nservices = myservices,!blockedservices\n```\n\n**Default:**\n```ini\nservices =\n```", .status = 0 }, - { .param = "port", .config = "conf", .section = "monitor", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_MONITOR` compilation flag)**\n\nUDP port for monitor.\n\n```ini\nport = 0 # monitor disabled\nport = 24480 # monitor on, port = 24480\n```\n\n**Example:**\n```ini\nport = 24480 # monitor on, port = 24480\n```", .status = 0 }, - { .param = "serverip", .config = "conf", .section = "monitor", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_MONITOR` compilation flag)**\n\nBind service to specified IP address.\n\n**Example:**\n```ini\nserverip = 192.168.178.1\n```\n\n**Default:**\n```ini\nserverip = # all IPs (default)\n```", .status = 0 }, - { .param = "nocrypt", .config = "conf", .section = "monitor", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_MONITOR` compilation flag)**\n\nUnsecured monitor connection [,IP address|IP address range]...\n\nPossible:\n- One or more IP addresses\n- One or more IP address ranges\n- Mixture of IP addresses and IP address ranges\n\n**Example:**\n```ini\nnocrypt = 127.0.0.1,192.168.0.0-192.168.255.255\n# Host 127.0.0.1 and IP range 192.168.0.0 to 192.168.255.255\n```\n\n**Default:**\n```ini\nnocrypt = # no secured monitor connection\n```", .status = 0 }, - { .param = "aulow", .config = "conf", .section = "monitor", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_MONITOR` compilation flag)**\n\nTime no EMM occurs so that client is set to low in minutes.\n\n**Example:**\n```ini\naulow = 30 # After 30 minutes without EMM client will be switched\n # from \"active\" to \"on\" (default)\n```", .status = 0 }, - { .param = "monlevel", .config = "conf", .section = "monitor", .text = "**🟢 Optional parameter**\n\n**(requires `MODULE_MONITOR` compilation flag)**\n\nMonitor-level.\n\n**Format:**\n```ini\nmonlevel = 0 # no access to monitor (default)\nmonlevel = 1 # only server and own procs\nmonlevel = 2 # all procs, but viewing only\nmonlevel = 3 # all procs, reload of oscam.user possible\nmonlevel = 4 # complete access\n```\n\n**Example:**\n```ini\nmonlevel = 4\n```\n\n**Default:**\n```ini\nmonlevel = 0\n```\n\nmonlevel can be overwritten per user in oscam.user!", .status = 0 }, - { .param = "File", .config = "conf", .section = "webif", .text = "⚠️ **Attention:**\n- File has to be in TXT format\n- The EMM-file should contain each PRE-CAM EMM in a new line\n- EMMs should be in HEX representation:\n - Example: `AABBCCDD...`\n- Spaces and tabs between the bytes are allowed:\n - `AA BB CC DD...`\n- The HEX representation of each EMM's byte can be represented by upper or lower case - even mixed is allowed:\n - `AA aa Aa aA...`\n- Other chars and comments are not allowed", .status = 0 }, - { .param = "httpport", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nPort for web interface.\n\n**Format:**\n```ini\nhttpport = 0 # disabled\nhttpport = port # Webinterface listening on http-port\nhttpport = +port # Webinterface listening on https-port (SSL), prefix + enables SSL\n```\n\n**Example:**\n```ini\nhttpport = 8888\nhttpport = +443\n```\n\n**Default:**\n```ini\nhttpport = 8888\n```", .status = 0 }, - { .param = "httpuser", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nUsername for password protection. Blank is default, which is strongly discouraged!\n\n**Example:**\n```ini\nhttpuser = myusername # all characters and figures are allowed\n```", .status = 0 }, - { .param = "httppwd", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nPassword for password protection.\n\n**Example:**\n```ini\nhttppwd = mypassword\n```\n\n⚠️ **Note:** The *user* and *pwd* parameters are queried when connecting to the webinterface in a message box. If they are missing or corrupted, a message \"Forbidden\" appears and the connection is aborted!", .status = 0 }, - { .param = "httpcss", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nPath for external CSS file.\n\nFor webinterface different styles are available. Put custom CSS files (ending with .css extension) in the oscam config directory to manage your custom styles with WebIf.\n\n**Example:**\n```ini\nhttpcss = /etc/oscam/harvest_round_Firefox.css\n```\n\n**Default:**\n```ini\nhttpcss = # embedded style is used (default)\n```\n\nTo see the current CSS style, use the URL: `http://url_to_oscam_webif/site.css`\n\nStyles can be found here: [Streamboard-Thread](http://www.streamboard.tv/wbb2/thread.php?threadid=30083)", .status = 0 }, - { .param = "httpjscript", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nPath for oscam.js javascript.\n\n**Format:**\n```ini\nhttpjscript = path\n```\n\n**Default:** none", .status = 0 }, - { .param = "httpscript", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nPath to an executable script which you wish to start from web interface.\n\n**Example:**\n```ini\nhttpscript = /path/to/script.sh\n```\n\n**Default:**\n```ini\nhttpscript = # no path\n```\n\nYou can run script file from script.html (SCRIPTS item in main menu). If the script file contains \"echo\", it will be displayed in web interface.\n\n**Error messages:**\n- If the file cannot run: `[Error]: Script \"name_of_script.sh\" not executable!`\n- If the file does not exist: `[Error]: Script \"name_of_script.sh\" not found!`", .status = 0 }, - { .param = "httptpl", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nPath for external templates and picons.\n\nMultiple simultaneously templates and picons are possible by creating sub folders (maximum length of 32 alphanumeric characters). Sub folders naming is corresponding to sub folder in URL.\n\n**Example:**\n```ini\nhttptpl = /this/is/my/path\n\n# Folder with multiple templates:\n# /this/is/my/path/template\n# /this/is/my/path/template2\n\n# Valid URLs:\n# http://host:port/template1\n# http://host:port/template2\n```\n\n**Default:**\n```ini\nhttptpl = # No external templates\n```", .status = 0 }, - { .param = "httppiconpath", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nPath to picon (channel logo) files. Picons are small images displayed in the WebIF to identify channels. The picons should be stored in this directory with specific naming conventions.\n\n**Supported picon naming formats:**\n```\nIC_caid_srvid.tpl\nIC_caid_provid_srvid.tpl\nIC_servicename.tpl\n```\n\n**Service name conversion rules:**\n- Convert all upper-case letters to lower case\n- Replace `*` with `star`\n- Replace `&` with `and`\n- Replace `+` with `plus`\n- Remove everything but a-z and 0-9\n- If service name ends with `hd` and picon is not found, fallback to name without `hd`\n\n**Format:**\n```ini\nhttppiconpath = path\n```\n\n**Example:**\n```ini\nhttppiconpath = /usr/share/oscam/picons\nhttppiconpath = /etc/oscam/picons\n```\n\n**Default:**\n```ini\nhttppiconpath =\n```\n\n⚠️ **Note:** To display picons in the user list, enable `httpshowpicons = 1`.", .status = 0 }, - { .param = "httphelplang", .config = "conf", .section = "webif", .text = "**🔴 Required parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nSet right language for wiki entry point.\n\n**Format:**\n```ini\nhttphelplang = de|en|fr # available wiki languages\n```", .status = 0 }, - { .param = "httplocale", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nSet the \"locale environment\".\n\n**Format:**\n```ini\nhttplocale = environment\n```\n\n**Default:** none\n\nSee: [http://en.wikipedia.org/wiki/locale](http://en.wikipedia.org/wiki/locale)", .status = 0 }, - { .param = "http_prepend_embedded_css", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nAdd embedded CSS before custom CSS.\n\n```ini\nhttp_prepend_embedded_css = 0 # Do not add the content of the embedded CSS\n # before the content of the custom CSS (default)\nhttp_prepend_embedded_css = 1 # embedded CSS will be added before external\n # custom CSS (specified by the httpcss parameter)\n```\n\n**Format:**\n```ini\nhttp_prepend_embedded_css = 0|1\n```\n\n**Example:**\n```ini\nhttp_prepend_embedded_css = 1\n```\n\n**Default:**\n```ini\nhttp_prepend_embedded_css = 0\n```\n\nThis parameter can be used to override the embedded CSS with custom styles. To see the current CSS styles use the URL: `http://url_to_oscam_webif/site.css`", .status = 0 }, - { .param = "httprefresh", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nStatus refresh in seconds.\n\n**Example:**\n```ini\nhttprefresh = 7 # status will be refreshed after 7 seconds\n```\n\n**Default:**\n```ini\nhttprefresh = # no refreshing\n```", .status = 0 }, - { .param = "httppollrefresh", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nRefresh time for polling in seconds.\n\n**Example:**\n```ini\nhttppollrefresh = 60 # polling will be refreshed after 60 seconds\n```\n\n**Default:**\n```ini\nhttppollrefresh = 0 # no refreshing poll\n```", .status = 0 }, - { .param = "httphideidleclients", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nEnables hiding clients after idle time set with parameter **hideclient_to** in section [monitor].\n\n```ini\nhttphideidleclients = 0 # hide not (default)\nhttphideidleclients = 1 # hide\n```\n\n**Format:**\n```ini\nhttphideidleclients = 0|1\n```\n\n**Example:**\n```ini\nhttphideidleclients = 1\n```\n\n**Default:**\n```ini\nhttphideidleclients = 0\n```", .status = 0 }, - { .param = "httphidetype", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nHide types in web interface status page.\n\n**Format:**\n```ini\nhttphidetype = type[type]...\n```\n\nWhere type = letter which defines types to hide (see Typ column):\n- s = server\n- h = http\n- m = monitor\n- r = reader\n- p = proxy\n- x = cacheex\n- c = client\n\n**Example:**\n```ini\nhttphidetype = sh # hide server- and http-type columns\n```\n\n**Default:**\n```ini\nhttphidetype = # hide none (default)\n```", .status = 0 }, - { .param = "httpshowpicons", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nShow picons in user list.\n\n```ini\nhttpshowpicons = 0 # default\nhttpshowpicons = 1 # show picons in userlist\n```\n\nIf this parameter is enabled, then a new column is added to the USERS tab which displays the picons of the last watched channels by active users. The folder where the picons must be configured in the httppiconpath.\n\n**Possible formats are:**\n```\nIC_caid_srvid.tpl\nIC_caid_provid_srvid.tpl\nIC_servicename.tpl\n```\n\nAdded support for picons by channel name:\n- Take service-name from oscam.srvid\n- Replace all upper-case letters with lower case\n- Replace * with star\n- Replace & with and\n- Replace + with plus\n- Remove everything but a-z and 0-9\n- If the result is name, the picon file will be `IC_name.tpl`\n\n**Example:**\n- Service-name: \"BBC-ONE +HD\"\n- Picon file: \"IC_bbconeplushd.tpl\"\n\nIf service-name ends with hd, and picon is not found, fallback to name without hd.", .status = 0 }, - { .param = "httppiconsize", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nHeight of picon images in pixels when displayed in WebIF.\n\n**Format:**\n```ini\nhttppiconsize = pixels\n```\n\n**Example:**\n```ini\nhttppiconsize = 40\n```\n\n**Default:**\n```ini\nhttppiconsize = 0\n```", .status = 0 }, - { .param = "httpshowmeminfo", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nDisplay memory usage information in Status screen.\n\n```ini\nhttpshowmeminfo = 0 # do not show (default)\nhttpshowmeminfo = 1 # display memory usage information in Status screen\n```\n\n**Format:**\n```ini\nhttpshowmeminfo = 0|1\n```\n\n**Example:**\n```ini\nhttpshowmeminfo = 1\n```\n\n**Default:**\n```ini\nhttpshowmeminfo = 0\n```", .status = 0 }, - { .param = "httpshowuserinfo", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nDisplay users information in Status screen.\n\n```ini\nhttpshowuserinfo = 0 # do not show (default)\nhttpshowuserinfo = 1 # display users information in Status screen\n```\n\n**Format:**\n```ini\nhttpshowuserinfo = 0|1\n```\n\n**Example:**\n```ini\nhttpshowuserinfo = 1\n```\n\n**Default:**\n```ini\nhttpshowuserinfo = 0\n```", .status = 0 }, - { .param = "httpshowreaderinfo", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nDisplay readers information in Status screen.\n\n```ini\nhttpshowreaderinfo = 0 # do not show (default)\nhttpshowreaderinfo = 1 # display readers information in Status screen\n```\n\n**Format:**\n```ini\nhttpshowreaderinfo = 0|1\n```\n\n**Example:**\n```ini\nhttpshowreaderinfo = 1\n```\n\n**Default:**\n```ini\nhttpshowreaderinfo = 0\n```", .status = 0 }, - { .param = "httpshowcacheexinfo", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nDisplay CacheEX information in Status screen.\n\n```ini\nhttpshowcacheexinfo = 0 # do not show (default)\nhttpshowcacheexinfo = 1 # display CacheEX information in Status screen\n```\n\n**Format:**\n```ini\nhttpshowcacheexinfo = 0|1\n```\n\n**Example:**\n```ini\nhttpshowcacheexinfo = 1\n```\n\n**Default:**\n```ini\nhttpshowcacheexinfo = 0\n```", .status = 0 }, - { .param = "httpshowecminfo", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nDisplay readers and users ECM information in Status screen.\n\n```ini\nhttpshowecminfo = 0 # do not show (default)\nhttpshowecminfo = 1 # display readers and users ECM information in Status screen\n```\n\n**Format:**\n```ini\nhttpshowecminfo = 0|1\n```\n\n**Example:**\n```ini\nhttpshowecminfo = 1\n```\n\n**Default:**\n```ini\nhttpshowecminfo = 0\n```", .status = 0 }, - { .param = "httpshowloadinfo", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nDisplay load average and CPU usage information in Status screen.\n\n```ini\nhttpshowloadinfo = 0 # do not show (default)\nhttpshowloadinfo = 1 # display load average and CPU usage information in Status screen\n```\n\n**Format:**\n```ini\nhttpshowloadinfo = 0|1\n```\n\n**Example:**\n```ini\nhttpshowloadinfo = 1\n```\n\n**Default:**\n```ini\nhttpshowloadinfo = 0\n```", .status = 0 }, - { .param = "httpallowed", .config = "conf", .section = "webif", .text = "**🔴 Required parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nHTTP web interface connections allowed. Blank is allowed (default), but that makes no sense! If the webinterface is to be used, then there must be a way to connect with it. Therefore we declare this parameter as **mandatory**!\n\nWith **::1** OSCam decides to resolve 'localhost' to **IPv6**!\n\n**Format:**\n```ini\nhttpallowed = IP address|IP address range[,IP address|IP address range,[::1]]...\n```\n\n**Example:**\n```ini\nhttpallowed = 127.0.0.1,192.168.0.0-192.168.255.255\n# Host and range 192.168.0 are allowed\n\nhttpallowed = 127.0.0.1,192.168.0.0-192.168.255.255,::1\n# Host and range 192.168.0 are allowed, resolving to IPv6\n```\n\n**Default:**\n```ini\nhttpallowed = 127.0.0.1,192.168.0.0-192.168.255.255,10.0.0.0-10.255.255.255,::1\n```", .status = 0 }, - { .param = "httpreadonly", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nRead only mode for web interface.\n\n```ini\nhttpreadonly = 0 # all is possible (default)\nhttpreadonly = 1 # only read\n```\n\n**Format:**\n```ini\nhttpreadonly = 0|1\n```\n\n**Example:**\n```ini\nhttpreadonly = 1\n```\n\n**Default:**\n```ini\nhttpreadonly = 0\n```", .status = 0 }, - { .param = "httpsavefullcfg", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nWrite config mode.\n\n```ini\nhttpsavefullcfg = 0 # all not empty parameters, all not default parameters,\n # all parameters not containing the same value as the same\n # parameter in global configuration (default)\nhttpsavefullcfg = 1 # all parameters\n```\n\n**Format:**\n```ini\nhttpsavefullcfg = 0|1\n```\n\n**Example:**\n```ini\nhttpsavefullcfg = 1\n```\n\n**Default:**\n```ini\nhttpsavefullcfg = 0\n```", .status = 0 }, - { .param = "httpoverwritebakfile", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nOverwrite backup configuration files (*.bak).\n\n```ini\nhttpoverwritebakfile = 0 # default\nhttpoverwritebakfile = 1 # overwrite backup configurations files\n```\n\n**Format:**\n```ini\nhttpoverwritebakfile = 0|1\n```\n\n**Example:**\n```ini\nhttpoverwritebakfile = 1\n```\n\n**Default:**\n```ini\nhttpoverwritebakfile = 0\n```", .status = 0 }, - { .param = "httpcert", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nFile for HTTP SSL certificate.\n\n**Example:**\n```ini\nhttpcert = oscam.cert\n```\n\n**Default:**\n```ini\nhttpcert = # file oscam.pem (embedded) is used\n```", .status = 0 }, - { .param = "https_force_secure_mode", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nForce secure HTTPS mode. When enabled, HTTP connections are not allowed.\n\n**Format:**\n```ini\nhttps_force_secure_mode = 0|1\n```\n\n**Example:**\n```ini\nhttps_force_secure_mode = 1\n```\n\n**Default:**\n```ini\nhttps_force_secure_mode = 1\n```", .status = 0 }, - { .param = "https_auto_create_cert", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nAutomatically create SSL certificate if no certificate file is available.\n\n**Format:**\n```ini\nhttps_auto_create_cert = 0|1\n```\n\n**Example:**\n```ini\nhttps_auto_create_cert = 1\n```\n\n**Default:**\n```ini\nhttps_auto_create_cert = 1\n```", .status = 0 }, - { .param = "httpdyndns", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nHTTP web interface connections allowed via hostname.\n\n**Format:**\n```ini\nhttpdyndns = hostname[,hostname][,hostname]\n```\n\n**Example:**\n```ini\nhttpdyndns = host1.example.com,host2.example.com\n```", .status = 0 }, - { .param = "aulow", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nTime no EMM occurs so that client is set to low in minutes.\n\n**Example:**\n```ini\naulow = 30 # After 30 minutes without EMM client will be switched\n # from \"active\" to \"on\" (default)\n```", .status = 0 }, - { .param = "hideclient_to", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nTime to hide clients in the monitor if not sending requests. See also parameter **httphideidleclients** in section [webif].\n\n```ini\nhideclient_to = 0 # no hide\nhideclient_to = 1 # hide clients\n```\n\n**Format:**\n```ini\nhideclient_to = seconds\n```\n\n**Example:**\n```ini\nhideclient_to = 120\n```\n\n**Default:**\n```ini\nhideclient_to = 0\n```", .status = 0 }, - { .param = "httposcamlabel", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nSet individual label in web interface header.\n\n**Format:**\n```ini\nhttposcamlabel = text\n```\n\n**Default:**\n```ini\nhttposcamlabel = OSCam\n```", .status = 0 }, - { .param = "httpemmuclean", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nMaximum size of unique EMM log in kB. When exceeded, older entries are cleaned up.\n\n**Format:**\n```ini\nhttpemmuclean = size_in_kb\n```\n\n**Example:**\n```ini\nhttpemmuclean = 512\n```\n\n**Default:**\n```ini\nhttpemmuclean = 256\n```\n\n`0` = no cleanup", .status = 0 }, - { .param = "httpemmsclean", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nMaximum size of shared EMM log in kB. When exceeded, older entries are cleaned up.\n\n**Format:**\n```ini\nhttpemmsclean = size_in_kb\n```\n\n**Example:**\n```ini\nhttpemmsclean = 256\n```\n\n**Default:**\n```ini\nhttpemmsclean = -1\n```\n\n`-1` = do not show log, `0` = no cleanup", .status = 0 }, - { .param = "httpemmgclean", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag)**\n\nMaximum size of global EMM log in kB. When exceeded, older entries are cleaned up.\n\n**Format:**\n```ini\nhttpemmgclean = size_in_kb\n```\n\n**Example:**\n```ini\nhttpemmgclean = 256\n```\n\n**Default:**\n```ini\nhttpemmgclean = -1\n```\n\n`-1` = do not show log, `0` = no cleanup", .status = 0 }, - { .param = "http_status_log", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF_LIVELOG` compilation flag)**\n\nDisplay log in Status screen.\n\n```ini\nhttp_status_log = 0 # do not show (default)\nhttp_status_log = 1 # display log in Status screen\n```\n\n**Format:**\n```ini\nhttp_status_log = 0|1\n```\n\n**Example:**\n```ini\nhttp_status_log = 1\n```\n\n**Default:**\n```ini\nhttp_status_log = 0\n```", .status = 0 }, - { .param = "http_extern_jquery", .config = "conf", .section = "webif", .text = "**🟢 Optional parameter**\n\n**(requires `WEBIF` compilation flag, only when `WEBIF_JQUERY` is not defined)**\n\nExternal URL for jQuery library. Used when jQuery is not embedded in the WebIF build.\n\n**Format:**\n```ini\nhttp_extern_jquery = URL\n```\n\n**Default:**\n```ini\nhttp_extern_jquery = //code.jquery.com/jquery-3.7.1.min.js\n```", .status = 0 }, - { .param = "Format", .config = "cacheex", .section = "", .text = "```ini\nm:[CAID][:][provider ID][:][service ID][:][ECM PID][:][CHID][:][ECM length 1[,ECM length 2]...]=\n [CAID][:][provider ID][:][service ID][:][ECM PID][:][CHID][:][ECM length 1[,ECM length 2]...]]\n```", .status = 0 }, - { .param = "Field", .config = "cacheex", .section = "", .text = "| Field | Description | Format | Required |\n|-------|-------------|--------|----------|\n| **m** | Mapping prefix | Fixed | Yes |\n| **CAID** | Conditional Access ID | 4-digit hexadecimal | Optional |\n| **provider ID** | Provider identifier | Hexadecimal | Optional |\n| **service ID** | Service identifier | Hexadecimal | Optional |\n| **ECM PID** | ECM Process ID | Hexadecimal | Optional |\n| **CHID** | Channel ID | Hexadecimal | Optional |\n| **ECM length** | ECM length in bytes | Decimal, comma-separated | Optional |\n| **=** | Separator between source and target | Fixed | Yes |\n\n**Syntax Rules**:\n- Empty fields are represented by consecutive colons (`::`)\n- Multiple ECM lengths are comma-separated (e.g., `93,95`)\n- Left side of `=` is the incoming request (from cache exchange partner)\n- Right side of `=` is the local cache lookup (what to search for locally)", .status = 0 }, - { .param = "Basic", .config = "cacheex", .section = "", .text = "Map CAID 1702 to CAID 1833 for ECM length 93:\n\n```ini\n# Sky Germany S02 to S02-Tunnel\nm:1702:::::93=1833:::::93\n```", .status = 0 }, - { .param = "Multiple", .config = "cacheex", .section = "", .text = "Match multiple ECM lengths for the same CAID mapping:\n\n```ini\n# ORF ICE mapping with multiple lengths\nm:09C4:::::46,58,90,95=09C7:::::46,58,90,95\n```", .status = 0 }, - { .param = "Provider-Specific", .config = "cacheex", .section = "", .text = "Map specific provider IDs:\n\n```ini\n# HD+ with provider ID\nm:1830:000000::::92=1830:003411::::92\n```", .status = 0 }, - { .param = "Service-Specific", .config = "cacheex", .section = "", .text = "Map specific service IDs:\n\n```ini\n# Map service 1234 to 5678\nm:1702::1234:::93=1833::5678:::93\n```", .status = 0 }, - { .param = "Real-World", .config = "cacheex", .section = "", .text = "```ini\n# Sky Germany mappings\nm:1702:::::93=1833:::::93\nm:1702:::::95=1833:::::95\n\n# HD+ mappings\nm:1830:003411::::92=1830:000000::::92\nm:1830:003411::::134=1830:000000::::134\n\n# ORF mappings\nm:0D95:::::144=0648:::::144\nm:0D98:::::144=0650:::::144\n\n# Viaccess mappings\nm:0500:023800::::188=0500:032830::::188\nm:0500:023800::::164=0500:032830::::164\n```", .status = 0 }, - { .param = "Complex", .config = "cacheex", .section = "", .text = "```ini\n# Complete oscam.cacheex file example\n\n# Sky Germany S02 standard lengths\nm:1702:::::93=1833:::::93\nm:1702:::::95=1833:::::95\nm:1702:::::144=1833:::::144\n\n# HD+ provider mapping\nm:1830:003411::::92=1830:000000::::92\nm:1830:003411::::134=1830:000000::::134\nm:1830:003411::::188=1830:000000::::188\n\n# ORF ICE to Cryptoworks mapping\nm:09C4:::::46,58,90,95=09C7:::::46,58,90,95\nm:0D95:::::144=0648:::::144\nm:0D98:::::144=0650:::::144\n\n# Viaccess TNTSAT to CSAT mapping\nm:0500:030B00::::188=0500:032830::::188\nm:0500:023800::::188=0500:032830::::188\n```", .status = 0 }, - { .param = "When", .config = "cacheex", .section = "", .text = "Use oscam.cacheex mappings when:\n- Partners use different CAIDs for the same content\n- You need to translate between tunnel CAIDs (e.g., 1702 ↔ 1833)\n- Provider IDs differ but ECM structure is identical\n- Service IDs need mapping between systems", .status = 0 }, - { .param = "When", .config = "cacheex", .section = "", .text = "You don't need oscam.cacheex if:\n- All partners use the same CAID structure\n- Using CE2 or CE3 modes without CAID translation\n- Simple cache sharing without mapping requirements", .status = 0 }, - { .param = "File", .config = "cacheex", .section = "", .text = "- **Comment Your Mappings**: Use `#` for comments to document each mapping purpose\n- **Test Incrementally**: Add mappings one at a time and verify functionality\n- **Monitor Cache Hits**: Check WebIF statistics to confirm mappings work\n- **Keep It Simple**: Only add mappings you actually need", .status = 0 }, - { .param = "Performance", .config = "cacheex", .section = "", .text = "- Each mapping adds minimal overhead to cache lookups\n- More specific mappings (with service IDs) are faster than generic ones\n- Use ECM length matching when possible to reduce false matches", .status = 0 }, - { .param = "Mapping", .config = "cacheex", .section = "", .text = "**Check the following**:\n1. Verify ECM lengths match exactly (check logs)\n2. Confirm CAID values are correct (4-digit hex)\n3. Ensure provider IDs match if specified\n4. Check that CE1 mode is enabled on the reader\n5. Review cache exchange statistics in WebIF\n\n**Common Issues**:\n- **Wrong ECM Length**: ECM length must match exactly between source and target\n- **Syntax Errors**: Missing colons or incorrect separator (must use `=`)\n- **Case Sensitivity**: CAID values must be uppercase hexadecimal\n- **File Not Loaded**: Check OSCam startup log for oscam.cacheex parsing errors", .status = 0 }, - { .param = "Verification", .config = "cacheex", .section = "", .text = "**Log Analysis**:\n```\n# Enable debug logging in oscam.conf\n[global]\nlogfile = /var/log/oscam/oscam.log\ndisablelog = 0\n```\n\nLook for cache exchange activity in logs showing CAID translation.\n\n**WebIF Statistics**:\n- Navigate to Status → Cache Exchange\n- Check \"ECM-CW received\" counters\n- Verify mapped CAIDs appear in statistics\n\n**Test Procedure**:\n1. Add mapping to oscam.cacheex\n2. Restart OSCam (or reload config if supported)\n3. Monitor logs during channel change\n4. Verify cache hit for mapped CAID\n5. Check that correct CW is returned", .status = 0 }, - { .param = "Syntax", .config = "cacheex", .section = "", .text = "**Valid Examples**:\n```ini\nm:1702:::::93=1833:::::93 # Valid: Basic CAID mapping\nm:1830:003411::::92=1830:000000::::92 # Valid: Provider mapping\nm:09C4:::::46,58,90=09C7:::::46,58,90 # Valid: Multiple lengths\n```\n\n**Invalid Examples**:\n```ini\nm:1702:::93=1833:::93 # Invalid: Missing colons\n1702:::::93=1833:::::93 # Invalid: Missing 'm:' prefix\nm:1702:::::93-1833:::::93 # Invalid: Wrong separator (use =)\nm:1702:::::93= # Invalid: Missing target\n```", .status = 0 }, - { .param = "Field", .config = "cacheex", .section = "", .text = "The field order is strict and must follow this pattern:\n```\nm:[CAID]:[ProvID]:[SrvID]:[PID]:[CHID]:[Length]=[CAID]:[ProvID]:[SrvID]:[PID]:[CHID]:[Length]\n └─1──┘ └──2──┘ └──3──┘ └─4─┘ └─5──┘ └──6───┘ └─1──┘ └──2──┘ └──3──┘ └─4─┘ └─5──┘ └──6───┘\n```", .status = 0 }, - { .param = "Comments", .config = "cacheex", .section = "", .text = "Comments can be added using `#`:\n```ini\n# This is a comment\nm:1702:::::93=1833:::::93 # Inline comment\n```", .status = 0 }, - { .param = "oscam", .config = "cacheex", .section = "", .text = "- `cacheexwaittime` - Wait time for CE1 response\n- `max_cache_time` - Cache retention time\n- `max_cache_count` - Maximum ECMs in cache\n\nSee the oscam.conf documentation for complete cache exchange settings.", .status = 0 }, - { .param = "oscam", .config = "cacheex", .section = "", .text = "- `cacheex` - Cache exchange mode (1, 2, or 3)\n- `cacheex_maxhop` - Maximum hops for cache forwarding\n- `cacheex_ecm_filter` - Filter which CAIDs are exchanged\n\nSee the oscam.server documentation for reader-specific cache exchange parameters.", .status = 0 }, - { .param = "oscam", .config = "cacheex", .section = "", .text = "- `cacheex` - User cache exchange permission\n- `cacheex_maxhop` - Maximum hops for this user\n\nSee the oscam.user documentation for user cache exchange settings.", .status = 0 }, - { .param = "disabled", .config = "user", .section = "account", .text = "**🟢 Optional parameter**\n\nAccount disabled.\n\n```ini\ndisabled = 0 # account enabled\ndisabled = 1 # account disabled\n```\n\n**Format:**\n```ini\ndisabled = 0|1\n```\n\n**Example:**\n```ini\ndisabled = 1\n```\n\n**Default:**\n```ini\ndisabled = 0\n```", .status = 0 }, - { .param = "user", .config = "user", .section = "account", .text = "**🔴 Required parameter**\n\nAccount name.\n\n**Example:**\n```ini\nuser = user1\n```\n\n**Default:**\n```ini\nuser =\n```", .status = 0 }, - { .param = "pwd", .config = "user", .section = "account", .text = "**🔴 Required parameter**\n\nPassword for account.\n\n⚠️ **Note:** Gbox Protocol: pwd is not required\n\n**Example:**\n```ini\npwd = pwuser1\n```\n\n**Default:**\n```ini\npwd =\n```", .status = 0 }, - { .param = "description", .config = "user", .section = "account", .text = "**🟢 Optional parameter**\n\nDescription of user account (text).\n\n**Format:**\n```ini\ndescription = text\n```\n\n**Example:**\n```ini\ndescription = Living room receiver\n```\n\n**Default:**\n```ini\ndescription =\n```", .status = 0 }, - { .param = "hostname", .config = "user", .section = "account", .text = "**🟢 Optional parameter**\n\nHost from which user connection is allowed.\n\n**Example:**\n```ini\nhostname = client.dyndns.org\n```\n\n**Default:**\n```ini\nhostname =\n```", .status = 0 }, - { .param = "caid", .config = "user", .section = "account", .text = "**🟢 Optional parameter**\n\nDefine and mapping of CAIDs for reader.\n\n**Format:**\n```ini\ncaid = [&][:][,[&][:target ]]...\n```\n\n**Example:**\n```ini\ncaid = 0100\ncaid = 0200&ffee:0300\ncaid = 0400&ff00:0500,0600\ncaid = 0702,0722\ncaid = 0702&ffdf # shortcut for the example above\n```\n\n**Default:** all CAIDs with mask FFFF", .status = 0 }, - { .param = "uniq", .config = "user", .section = "account", .text = "**🟢 Optional parameter**\n\nUnique connection mode for user.\n\n```ini\nuniq = 0 # disabled, default\nuniq = 1 # only one connection per user is allowed\nuniq = 2 # set user to fake if source ip is different\n # (e.g. for newcamd clients with different CAIDs and ports)\nuniq = 3 # only one connection per user, but only the last login will survive (old mpcs behavior)\nuniq = 4 # set user only to fake if source ip is different, but only the last login will survive\n```\n\n**Format:**\n```ini\nuniq = 0|1|2|3|4\n```\n\n**Example:**\n```ini\nuniq = 1\n```\n\n**Default:**\n```ini\nuniq = 0\n```", .status = 0 }, - { .param = "sleepsend", .config = "user", .section = "account", .text = "**🟢 Optional parameter**\n\nSleep send mode.\n\n```ini\nsleepsend = 0\nsleepsend = 255 # OSCam client only: stopping requests until next zap\n # camd 3.x only: stopping requests until restart of camd3 client\n```\n\n**Format:**\n```ini\nsleepsend = 0-255\n```\n\n**Example:**\n```ini\nsleepsend = 255\n```\n\n**Default:**\n```ini\nsleepsend =\n```", .status = 0 }, - { .param = "failban", .config = "user", .section = "account", .text = "**🟢 Optional parameter**\n\nMask for IP based blocking:\n\n```ini\nfailban = 0 # ignore (default)\nfailban = 2 # block IP address of a disabled account on connecting\nfailban = 4 # block IP address of a sleeping account while sleeping comes up\nfailban = 8 # block duplicate IP address\n```\n\n**Format:**\n```ini\nfailban = 0|2|4|8\n```\n\n**Example:**\n```ini\nfailban = 2\n```\n\n**Default:**\n```ini\nfailban = 0\n```", .status = 0 }, - { .param = "monlevel", .config = "user", .section = "account", .text = "**🟢 Optional parameter**\n\nMonitor level:\n\n```ini\nmonlevel = 0 # no access to monitor\nmonlevel = 1 # only server and own procs\nmonlevel = 2 # all procs, but viewing only (default)\nmonlevel = 3 # all procs, reload of oscam.user possible\nmonlevel = 4 # complete access\n```\n\n**Format:**\n```ini\nmonlevel = 0|1|2|3|4\n```\n\n**Example:**\n```ini\nmonlevel = 4\n```\n\n**Default:**\n```ini\nmonlevel = 2\n```", .status = 0 }, - { .param = "sleep", .config = "user", .section = "account", .text = "**🟢 Optional parameter**\n\nTime waiting for inactive user in minutes.\n\n**Format:**\n```ini\nsleep = minutes\n```\n\n**Example:**\n```ini\nsleep = 5\n```\n\n**Default:**\n```ini\nsleep =\n```", .status = 0 }, - { .param = "suppresscmd08", .config = "user", .section = "account", .text = "**🟢 Optional parameter**\n\nSwitches suppress of CMD08.\n\n```ini\nsuppresscmd08 = 0 # CMD08 for camd3 3.57x/3.78x clients enabled\nsuppresscmd08 = 1 # CMD08 for camd3 3.57x/3.78x clients disabled\n```\n\n**Format:**\n```ini\nsuppresscmd08 = 0|1\n```\n\n**Example:**\n```ini\nsuppresscmd08 = 1\n```\n\n**Default:**\n```ini\nsuppresscmd08 = 0\n```", .status = 0 }, - { .param = "umaxidle", .config = "user", .section = "account", .text = "**🟢 Optional parameter**\n\nValue for user being idle before disconnect (seconds).\n\n```ini\numaxidle = -1 # use clientmaxidle in [global]-section\numaxidle = 0 # idle disconnect disabled (default)\n```\n\n**Format:**\n```ini\numaxidle = -1|0|seconds\n```\n\n**Example:**\n```ini\numaxidle = 300\n```\n\n**Default:**\n```ini\numaxidle = 0\n```", .status = 0 }, - { .param = "keepalive", .config = "user", .section = "account", .text = "**🟢 Optional parameter**\n\nDisable keepalive between newcamd-server and client connection.\n\n```ini\nkeepalive = 0 # disabled\nkeepalive = 1 # enabled (default)\n```\n\n**Format:**\n```ini\nkeepalive = 0|1\n```\n\n**Example:**\n```ini\nkeepalive = 0\n```\n\n**Default:**\n```ini\nkeepalive = 1\n```", .status = 0 }, - { .param = "au", .config = "user", .section = "account", .text = "**🟢 Optional parameter**\n\nAU (Auto Update) settings.\n\n**Format:**\n```ini\nau =