/* Citrix Published Application Scanner */
/* By Ian.Vitek@ixsecurity.com          */
/* citrix-pa-scan [option]              */
/* Where option is:                     */
/* IP to test IP                        */
/* - to read IPs from STDIN             */
/* file to read IPs from file           */
/* random to read IPs from /dev/urandom */

#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
static int sockfd;

int scan (char *ctarget,int timeout) {
    int n,i,newHost=1,flag1,loop=1;
    struct sockaddr_in servaddr;
    unsigned char recvline[10000];
    unsigned char sendline[] =
    "\x2a\x00\x01\x32\x02\xfd"
    "\xa8\xe3\x00\x00\x00\x00"
    "\x00\x00\x00\x00\x00\x00"
    "\x00\x00\x00\x00\x00\x00"
    "\x00\x00\x00\x00\x21\x00"
    "\x02\x00\x00\x00\x00\x00"
    "\x00\x00\x00\x00\x00"
    ;

    int hi,ch;
    int ch1,ch2,ch3,ch4;
    char target[512];
    FILE *inputfd=NULL;
    FILE *urand;

    if (!strcmp(ctarget, "-")) {
      inputfd = stdin;
      newHost=2;
    } else {
      if( (inputfd = fopen(ctarget, "r") ) != NULL) {
      newHost=2;
      }
    }

    if(!strcmp(ctarget,"random")) {
      newHost=3;
      if( (urand=fopen("/dev/urandom", "rb") ) == NULL) {
        printf("Cant open /dev/urandom\n\n");
        exit(1);
      }
    }

    while(loop==1) {
    if(inputfd && newHost==2) {
      loop=0;
      hi=0;
      target[0]=0x00;
      while((ch=getc(inputfd)) != EOF) {
        if(ch==' ' || ch=='\n' || ch=='\t' || ch=='\0') {
          break;
        }
        if (hi<511) {
          loop=1;
          target[hi++] = (char) ch;
        } else {
          printf("One of the host_specifications from your input file 
is too long (> %d chars)\n\n", sizeof(target));
          exit(1);
        }
      }
      target[hi] = '\0';
    } else if(newHost==1 && strlen(ctarget)<511) {
      strcpy(target, ctarget);
      loop=0;
    } else if(newHost==3) {
      loop=1;
      do {
        ch1=getc(urand);
      } while (ch1<1 || ch1>254);
      ch2=getc(urand);
      ch3=getc(urand);
      do {
        ch4=getc(urand);
      } while (ch4<1 || ch4>254);
      sprintf(target,"%d.%d.%d.%d", ch1, ch2, ch3, ch4);
    } else {
      printf("Nothing to do? Right input file or IP adress?\n\n");
      exit(1);
    }
    if(target[0]==0x00) { printf("\n"); exit(1); }

    sockfd=socket(AF_INET,SOCK_DGRAM,0);

    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr=inet_addr(target);
    servaddr.sin_port=htons(1604);

    alarm(timeout);
    sendto(sockfd,sendline,sizeof(sendline),0,
           (struct sockaddr *)&servaddr,sizeof(servaddr));
    n=recvfrom(sockfd,recvline,10000,0,NULL,NULL);
    close(sockfd);
    recvline[n]=0;
    alarm(0);
    flag1=0;
    if(n>37) {
      for(i=40; i<n; i++) {
        if(recvline[i] != 0x00) {
          if(flag1==0) {
            printf("\n\n%15s: ",target);
            flag1=1;
          }
          printf("%c",recvline[i]);
        } else {
          printf("\n                 ");
        }
      }
      if(recvline[38] == 0xe4 && recvline[39] == 0x04) {
        printf("\n\n%15s: No Published Application\n",target);
      }
    }
    }
}

void gotAlarm () {
    close(sockfd);
}


int main(int argc, char**argv)
{
    int t=1;
    printf("\nCitrix Published Application Scanner version 1.0\n");
    printf("By Ian Vitek, ian.vitek@ixsecurity.com\n");
    if (argc < 2)
    {
       printf("usage: %s { IP | file | - | random } [timeout sec]\n\n",argv[0]);
       exit(1);
    }

    if(argv[2]) t=atoi(argv[2]);
    signal (SIGALRM, gotAlarm);
    scan(argv[1],t);

    printf("\n");

}
