text: /*
   * Copyright (c) 2015 Kaprica Security, Inc.
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy
   * of this software and associated documentation files (the "Software"), to deal
   * in the Software without restriction, including without limitation the rights
   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   * copies of the Software, and to permit persons to whom the Software is
   * furnished to do so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in
   * all copies or substantial portions of the Software.
   *
   * 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 THE
   * AUTHORS OR COPYRIGHT HOLDERS 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.
   *
   */
  #include "cgc_stdlib.h"
  #include "cgc_stdint.h"
  #include "cgc_string.h"
  #include "cgc_endian.h"
  #include "cgc_io.h"
  #include "cgc_protocols.h"
  #include "cgc_time.h"
  #include "cgc_vault.h"
  
  #define VAULT_SIZE 500
  
  typedef struct {
      void *data;
      unsigned int len;
  } locker_t;
  
  typedef struct {
      unsigned long long open_time;
      unsigned int open_length;
      locker_t contents[VAULT_SIZE];
      unsigned int num_contents;
  } vault_t;
  
  vault_t *the_vault;
  
  static void write_msg(uint8_t cmd, void *data, cgc_size_t n)
  {
      uint8_t hdr[7];
      
      n++; /* for cmd byte */
      *(uint16_t *)&hdr[0] = htobe16(PROTOCOL_VAULT);
      if (n < 0x8000)
      {
          *(uint16_t *)&hdr[2] = htobe16(n);
          hdr[4] = cmd;
          cgc_write_bytes(hdr, 5);
      }
      else
      {
          *(uint32_t *)&hdr[2] = htobe32(n | 0x80000000);
          hdr[6] = cmd;
          cgc_write_bytes(hdr, 7);
      }
  
      cgc_write_bytes(data, n-1);
  }
  
  void cgc_init_vault()
  {
      the_vault = cgc_malloc(sizeof(vault_t));
      /* 2014-12-24 23:00:00 */
      the_vault->open_time = ((2208988800ULL + 1419462000) * 1000);
      the_vault->open_length = (3600 * 1000);
      the_vault->num_contents = 0;
  }
  
  int cgc_handle_msg_vault(void *data, unsigned int n)
  {
      uint8_t cmd;
      uint32_t id;
  
      if (n < 1)
          return 0;
  
      cmd = *(uint8_t *)data;
      n--;
      data++;
  
      if (cmd == 1) /* LIST */
      {
          int i;
          uint32_t *buf = cgc_malloc(the_vault->num_contents * 8);
          if (buf == NULL)
          {
              write_msg(1, NULL, 0);
          }
          else
          {
              for (i = 0; i < the_vault->num_contents; i++)
              {
                  buf[i * 2] = htobe32((uint32_t)&the_vault->contents[i]);
                  buf[i * 2 + 1] = htobe32(the_vault->contents[i].len);
              }
              
              write_msg(1, buf, the_vault->num_contents * 8);
              cgc_free(buf);
          }
      }
      else if (cmd == 2) /* STORE */
      {
          id = htobe32(cgc_store_in_vault(0, data, n));
          write_msg(2, &id, sizeof(uint32_t));
      }
      else if (cmd == 3 && n >= 4) /* UPDATE */
      {
          id = betoh32(*(uint32_t *)data);
          id = htobe32(cgc_store_in_vault(id, data + 4, n - 4));
          write_msg(3, &id, sizeof(uint32_t));
      }
      else if (cmd == 4 && n >= 4) /* RETRIEVE */
      {
          void *outdata;
          unsigned int len;
          id = betoh32(*(uint32_t *)data);
          outdata = cgc_retrieve_from_vault(id, &len);
          if (outdata == NULL)
              write_msg(4, NULL, 0);
          else
              write_msg(4, outdata, len);
          cgc_free(outdata);
      }
  
      return 1;
  }
  
  uint32_t cgc_store_in_vault(uint32_t id, void *data, unsigned int n)
  {
      locker_t *locker;
      void *copy;
  
      if (id == 0)
      {
          if (the_vault->num_contents >= VAULT_SIZE)
              return 0;
          locker = &the_vault->contents[the_vault->num_contents++];
      }
      else
      {
          locker = (void *)id;
          if (locker >= &the_vault->contents[the_vault->num_contents])
              return 0;
  #ifdef PATCHED
          if (locker < &the_vault->contents[0] || ((intptr_t)locker - (intptr_t)&the_vault->contents[0]) % sizeof(locker_t))
              return 0;
  #endif
      }
  
      copy = cgc_malloc(n);
      if (copy == NULL)
          return 0;
  
      cgc_memcpy(copy, data, n);
      locker->data = copy;
      locker->len = n;
      return (uint32_t)locker;
  }
  
  void* cgc_retrieve_from_vault(uint32_t id, unsigned int *outlen)
  {
      if (cgc_current_time >= the_vault->open_time && cgc_current_time < the_vault->open_time + the_vault->open_length)
      {
          locker_t *locker = (void *)id;
  #ifdef PATCHED
          if (locker < &the_vault->contents[0] || locker >= &the_vault->contents[the_vault->num_contents] || ((intptr_t)locker - (intptr_t)&the_vault->contents[0]) % sizeof(locker_t))
              return NULL;
  #endif
          void *retval = locker->data;
  
          *outlen = locker->len;
          locker->data = NULL;
          locker->len = 0;
          return retval;
      }
  
      return NULL;
  }
  