Beispiel #1
0
/* Generate the full name of a particular pk group. */
char *ssh_pk_group_object_name(SshPkGroupObject group)
{
  unsigned char *str = NULL;

  if (group->diffie_hellman == NULL_FNPTR)
    ssh_dsprintf(&str, "%s", group->type->name);
  else
    ssh_dsprintf(&str, "%s{dh{%s}}", group->type->name,
                 group->diffie_hellman->name);

  return (char *) str;
}
Beispiel #2
0
/* This function takes a traffic selector and formats it as
   a string. This will return the allocated string inside
   the `str' argument. The `str' needs to be freed after it
   is no longer needed. Returns the number of characters
   written.*/
int ssh_ikev2_ts_to_string(char **str, SshIkev2PayloadTS ts)
{
  return ssh_dsprintf((unsigned char **) str, "%@", ssh_ikev2_ts_render, ts);
}
Beispiel #3
0
/*
 * Parse incoming socks connection from buffer. Consume the request
 * packet data from buffer. If everything is ok it allocates SocksInfo
 * strcture and store the request fields in it (sets
 * socks_version_number, command_code, ip, port, username). Returns
 * SSH_SOCKS_SUCCESS, SSH_SOCKS_TRY_AGAIN, or SSH_SOCKS_ERROR_*. If
 * anything other than SSH_SOCKS_SUCCESS is returned the socksinfo is
 * set to NULL.  Use ssh_socks_free to free socksinfo data.
 */
SocksError ssh_socks_server_parse_open(SshBuffer buffer, SocksInfo *socksinfo)
{
  unsigned char *data, *ip;
  unsigned long i, port;
  unsigned int version, cmd, ip_addr_len, atyp;
  unsigned char *username = NULL;
  size_t ret, len, bytes = 0;

  *socksinfo = NULL;
  len = ssh_buffer_len(buffer);
  data = ssh_buffer_ptr(buffer);

  if (len < 1)
    return SSH_SOCKS_TRY_AGAIN;

  version = data[0];
  bytes++;

  if (version != 4 && version != 5)
    {
      SSH_DEBUG(2, ("Server gave us version %d.", version));
      return SSH_SOCKS_ERROR_UNSUPPORTED_SOCKS_VERSION;
    }

  if (version == 4)
    {
      /* Check if enough data for header and name */
      if (len < SOCKS4_COMMAND_SIZE + 1)
        {
          return SSH_SOCKS_TRY_AGAIN;
        }


      /* Find the end of username */
      for (i = SOCKS4_COMMAND_SIZE; i < len; i++)
        {
          if (data[i] == '\0')
            break;
        }

      /* End of username not found, return either error or try_again */
      if (i == len || data[i] != '\0')
        {
          if (len > SOCKS4_COMMAND_SIZE + SOCKS4_MAX_NAME_LEN)
            {
              return SSH_SOCKS_ERROR_PROTOCOL_ERROR;
            }
          return SSH_SOCKS_TRY_AGAIN;
        }

      cmd = data[1];

      port = SSH_GET_16BIT(&data[2]);

      ip_addr_len = 4;
      ip = ssh_memdup(&data[4], ip_addr_len);
      atyp = SSH_SOCKS5_ATYP_IPV4;

      if (ip == NULL)
        {
          SSH_DEBUG(2, ("Failed to allocate IP-address buffer."));
          return SSH_SOCKS_ERROR_INVALID_ARGUMENT;
        }

      username = ssh_strdup((char *)(data + SOCKS4_COMMAND_SIZE));
      bytes = SOCKS4_COMMAND_SIZE +
        strlen((char *) data + SOCKS4_COMMAND_SIZE) + 1;
    }
  else
    {
      unsigned char port_buf[2];

      if (len - bytes < 3)
        return SSH_SOCKS_TRY_AGAIN;

      ret = ssh_decode_array(data + bytes, len - bytes,
                             SSH_DECODE_CHAR(&cmd),
                             SSH_DECODE_CHAR(NULL), /* RSV */
                             SSH_DECODE_CHAR(&atyp),
                             SSH_FORMAT_END);
      if (ret <= 0)
        {
          SSH_DEBUG(2, ("Failed to decode command packet."));
          return SSH_SOCKS_ERROR_PROTOCOL_ERROR;
        }
      bytes += ret;
      if (atyp == SSH_SOCKS5_ATYP_IPV4)
        {
          SSH_DEBUG(4, ("SOCKS5 received address type IPV4."));
          ip_addr_len = 4;
        }
      else if (atyp == SSH_SOCKS5_ATYP_IPV6)
        {
          SSH_DEBUG(4, ("SOCKS5 received address type IPV6."));
          ip_addr_len = 16;
        }
      else if (atyp == SSH_SOCKS5_ATYP_FQDN)
        {
          if (len - bytes < 1)
            return SSH_SOCKS_TRY_AGAIN;

          ip_addr_len = *(data + bytes);
          if (ip_addr_len <= 0 || ip_addr_len >= 255)
            {
              SSH_DEBUG(2, ("Invalid FQDN address len %d.", ip_addr_len));
              return SSH_SOCKS_ERROR_PROTOCOL_ERROR;
            }
          SSH_DEBUG(4, ("SOCKS5 received address type FQDN, len %d.",
                        ip_addr_len));
          bytes++;
        }
      else
        {
          SSH_DEBUG(2, ("Invalid address type %d.", atyp));
          return SSH_SOCKS_ERROR_PROTOCOL_ERROR;
        }
      /* ip addr len + port */
      if (len - bytes < ip_addr_len + 2)
        return SSH_SOCKS_TRY_AGAIN;

      ip = ssh_calloc(ip_addr_len + 1, sizeof(unsigned char));
      if (ip == NULL)
        {
          SSH_DEBUG(2, ("Failed to allocate IP-address buffer."));
          return SSH_SOCKS_ERROR_INVALID_ARGUMENT;
        }
      ret = ssh_decode_array(data + bytes, len - bytes,
                             SSH_DECODE_DATA(ip, ip_addr_len),
                             SSH_DECODE_DATA(port_buf, 2),
                             SSH_FORMAT_END);
      if (ret <= 0)
        {
          SSH_DEBUG(2, ("Failed to decode command packet."));
          ssh_free(ip);
          return SSH_SOCKS_ERROR_PROTOCOL_ERROR;
        }
      port = SSH_GET_16BIT(port_buf);
      bytes += ret;
    }

  if ((*socksinfo = ssh_calloc(1, sizeof(struct SocksInfoRec))) == NULL)
    {
      SSH_DEBUG(2, ("Failed to allocate SocksInfo."));
      ssh_free(ip);
      return SSH_SOCKS_ERROR_INVALID_ARGUMENT;
    }

  if (atyp == SSH_SOCKS5_ATYP_FQDN)
    {
      (*socksinfo)->ip = ip;
    }
  else
    {
      SshIpAddrStruct ip_addr;
      unsigned char buf[SSH_IP_ADDR_STRING_SIZE];

      SSH_IP_DECODE(&ip_addr, ip, ip_addr_len);

      ssh_ipaddr_print(&ip_addr, buf, sizeof(buf));
      (*socksinfo)->ip = ssh_memdup(buf, ssh_ustrlen(buf));
      ssh_free(ip);
      if ((*socksinfo)->ip == NULL)
        {
          SSH_DEBUG(2, ("Failed to allocate final IP-addr buf."));
          return SSH_SOCKS_ERROR_INVALID_ARGUMENT;
        }
    }

  (*socksinfo)->socks_version_number = version;
  (*socksinfo)->command_code = cmd;
  ssh_dsprintf(&(*socksinfo)->port, "%lu", port);
  (*socksinfo)->username = username;
  ssh_buffer_consume(buffer, bytes);
  SSH_DEBUG(5, ("Decoded %zd bytes.", bytes));
  return SSH_SOCKS_SUCCESS;
}
Beispiel #4
0
/*
 * Parse socks reply packet. Consume the reply packet data from buffer.
 * If the request was not granted (returns SSH_SOCKS_FAILED_*) the socket can
 * be immediately closed down (there will not be any additional data from the
 * socks server.
 * If the request is granted allocate socksinfo structure and store information
 * from request packet to there (sets socks_version_number, command_code, ip,
 * and port fields).
 * Use ssh_socks_free to free socksinfo data.
 */
SocksError ssh_socks_client_parse_reply(SshBuffer buffer,
                                        SocksInfo *socksinfo)
{
  unsigned char *data, *ip_ptr, *port_ptr;
  unsigned char *username =NULL;
  unsigned long len, port, version;
  size_t bytes = 0;
  unsigned int cmd, atyp, ip_addr_len;

  if (socksinfo)
    *socksinfo = NULL;
  len = ssh_buffer_len(buffer);
  data = ssh_buffer_ptr(buffer);

  /* Check if enough data for version. */
  if (len < 1)
    return SSH_SOCKS_TRY_AGAIN;

  version = data[0];
  /* SOCKS4 replys have version number '0'. Go figure. */
  if (version == 0)
    version = 4;
  bytes++;

  if (version != 4 && version != 5)
    {
      SSH_DEBUG(2, ("Server gave us version %ld.", version));
      return SSH_SOCKS_ERROR_UNSUPPORTED_SOCKS_VERSION;
    }

  if (version == 4)
    {
      /* A SOCKS4 command reply is exactly 8 bytes long. */
      if (len < 8)
        return SSH_SOCKS_TRY_AGAIN;
      SSH_DEBUG(2, ("Doing SOCKS4."));
      bytes = 8;

      if (data[1] != SSH_SOCKS4_REPLY_GRANTED)
        {
          SocksError error = SSH_SOCKS_ERROR_PROTOCOL_ERROR;
          switch (data[1])
            {
            case SSH_SOCKS4_REPLY_FAILED_REQUEST:
              error = SSH_SOCKS_FAILED_REQUEST;
              break;
            case SSH_SOCKS4_REPLY_FAILED_IDENTD:
              error = SSH_SOCKS_FAILED_IDENTD;
              break;
            case SSH_SOCKS4_REPLY_FAILED_USERNAME:
              error = SSH_SOCKS_FAILED_USERNAME;
              break;
            default:
              error = SSH_SOCKS_ERROR_PROTOCOL_ERROR;
              break;
            }
          ssh_buffer_consume(buffer, bytes);
          return error;
        }

      cmd = data[1];
      port_ptr = &data[2];
      ip_ptr = &data[4];
      ip_addr_len = 4;
      atyp = SSH_SOCKS5_ATYP_IPV4;
      username = (unsigned char *)&data[8];
    }
  else
    {
      size_t ret = 0L;

      /* SOCKS5. */
      if (len - bytes < 3)
        return SSH_SOCKS_TRY_AGAIN;

      ret = ssh_decode_array(data + bytes, len - bytes,
                             SSH_DECODE_CHAR(&cmd),
                             SSH_DECODE_CHAR(NULL), /* RSV */
                             SSH_DECODE_CHAR(&atyp),
                             SSH_FORMAT_END);
      if (ret == 0)
        {
          SSH_DEBUG(2, ("Decoding reply packet failed."));
          return SSH_SOCKS_ERROR_PROTOCOL_ERROR;
        }
      bytes += ret;
      if (atyp == SSH_SOCKS5_ATYP_IPV4)
        {
          ip_addr_len = 4;
        }
      else if (atyp == SSH_SOCKS5_ATYP_IPV6)
        {
          ip_addr_len = 16;
        }
      else if (atyp == SSH_SOCKS5_ATYP_FQDN)
        {
          if (len - bytes < 1)
            return SSH_SOCKS_TRY_AGAIN;
          ret = ssh_decode_array(data + bytes, len - bytes,
                                 SSH_DECODE_CHAR(&ip_addr_len),
                                 SSH_FORMAT_END);
          if (ret == 0)
            {
              SSH_DEBUG(2, ("Decoding FQDN hostname len failed."));
              return SSH_SOCKS_ERROR_PROTOCOL_ERROR;
            }
          bytes += ret;
        }
      else
        {
          SSH_DEBUG(2, ("Invalid address type %d.", atyp));
          return SSH_SOCKS_ERROR_PROTOCOL_ERROR;
        }
      /* ip addr len + port (2 bytes) */
      if (len - bytes < ip_addr_len + 2)
        return SSH_SOCKS_TRY_AGAIN;

      ip_ptr = data + bytes;
      if (ret == 0)
        {
          SSH_DEBUG(2, ("Decoding reply packet failed."));
          return SSH_SOCKS_ERROR_PROTOCOL_ERROR;
        }
      bytes += ip_addr_len;

      port_ptr = data + bytes;
      bytes += 2;
      SSH_DEBUG(2, ("Doing SOCKS5."));

      if (cmd != SSH_SOCKS5_REPLY_SUCCESS)
        {
          SSH_DEBUG(2, ("Got reply %d from server.", cmd));
          if (cmd < SSH_SOCKS5_REPLY_SUCCESS ||
              cmd > SSH_SOCKS5_REPLY_ATYP_NOT_SUPPORTED)
            return SSH_SOCKS_ERROR_PROTOCOL_ERROR;
          return SSH_SOCKS_FAILED_REQUEST;
        }
    }

  if (socksinfo)
    {
      SshIpAddrStruct ip_addr;

      if ((*socksinfo = ssh_calloc(1, sizeof(SocksInfoStruct))) == NULL)
        {
          SSH_DEBUG(2, ("Couldn't allocate SocksInfo."));
          return SSH_SOCKS_ERROR_INVALID_ARGUMENT;
        }

      memset(&ip_addr, 0, sizeof(ip_addr));
      (*socksinfo)->socks_version_number = version;
      (*socksinfo)->command_code = cmd;

      port = SSH_GET_16BIT(port_ptr);
      ssh_dsprintf(&(*socksinfo)->port, "%lu", port);
      if (username)
        (*socksinfo)->username = ssh_strdup(username);
      else
        (*socksinfo)->username = NULL;

      if (atyp == SSH_SOCKS5_ATYP_FQDN)
        {
          (*socksinfo)->ip = ssh_calloc(ip_addr_len + 1, sizeof(char));
          if ((*socksinfo)->ip)
            memmove((*socksinfo)->ip, ip_ptr, ip_addr_len);
        }
      else
        {
          unsigned char buf[SSH_IP_ADDR_STRING_SIZE];

          SSH_IP_DECODE(&ip_addr, ip_ptr, ip_addr_len);
          ssh_ipaddr_print(&ip_addr, buf, sizeof(buf) - 1);
          (*socksinfo)->ip = ssh_strdup(buf);
        }
    }

  SSH_DEBUG(2, ("Decoded %zd bytes.", bytes));
  ssh_buffer_consume(buffer, bytes);
  return SSH_SOCKS_SUCCESS;
}
int main(int ac, char **av)
{
  int opt, i;
  DIR *ssh2dir = NULL;
  char *ssh2dirname;
  Boolean dynamic_array = FALSE;
  struct dirent * cand;

  /* Save program name. */
  if (strchr(av[0], '/'))
    av0 = strrchr(av[0], '/') + 1;
  else
    av0 = av[0];

  user = ssh_user_initialize(NULL, FALSE);

#ifdef WITH_PGP
  pgp_keyring = ssh_xstrdup(SSH_PGP_SECRET_KEY_FILE);
#endif /* WITH_PGP */

  action = ADD;
  while ((opt = ssh_getopt(ac, av, "ldDput:f:F:1LUNPI", NULL)) != EOF)
    {
      if (!ssh_optval)
        {
          usage();
          exit(EXIT_STATUS_ERROR);
        }
      switch (opt)
        {
        case 'N':
#ifdef WITH_PGP
          pgp_mode = PGP_KEY_NAME;
#else /* WITH_PGP */
          fprintf(stderr, "%s: PGP keys not supported.\n", av0);
          exit(EXIT_STATUS_ERROR);
#endif /* WITH_PGP */
          break;

        case 'P':
#ifdef WITH_PGP
          pgp_mode = PGP_KEY_FINGERPRINT;
#else /* WITH_PGP */
          fprintf(stderr, "%s: PGP keys not supported.\n", av0);
          exit(EXIT_STATUS_ERROR);
#endif /* WITH_PGP */
          break;

        case 'I':
#ifdef WITH_PGP
          pgp_mode = PGP_KEY_ID;
#else /* WITH_PGP */
          fprintf(stderr, "%s: PGP keys not supported.\n", av0);
          exit(EXIT_STATUS_ERROR);
#endif /* WITH_PGP */
          break;

        case 'R':
#ifdef WITH_PGP
          ssh_xfree(pgp_keyring);
          pgp_keyring = ssh_xstrdup(ssh_optarg);
#else /* WITH_PGP */
          fprintf(stderr, "%s: PGP keys not supported.\n", av0);
          exit(EXIT_STATUS_ERROR);
#endif /* WITH_PGP */
          break;

        case 'l':
          action = LIST;
          break;

        case 'p':
          use_stdin = TRUE;
          break;

        case 'd':
          if (action == ADD_URL)
            action = DELETE_URL;
          else
            action = DELETE;
          break;

        case 'D':
          action = DELETE_ALL;
          break;

        case 't':
          if (ssh_optargnum)
            {
              key_timeout = (SshTime)(ssh_optargval * 60);
            }
          else
            {
              usage();
              exit(EXIT_STATUS_ERROR);
            }
          have_attrs = TRUE;
          break;

        case 'f':
          if (ssh_optargnum)
            {
              path_limit = (SshUInt32)ssh_optargval;
            }
          else
            {
              usage();
              exit(EXIT_STATUS_ERROR);
            }
          have_attrs = TRUE;
          break;

        case 'F':
          path_constraint = ssh_xstrdup(ssh_optarg);
          have_attrs = TRUE;
          break;

        case '1':
          forbid_compat = TRUE;
          have_attrs = TRUE;
          break;

        case 'u':
          if (action == DELETE)
            action = DELETE_URL;
          else
            action = ADD_URL;
          break;

        case 'L':
          action = LOCK;
          break;

        case 'U':
          action = UNLOCK;
          break;

        default:
          usage();
          exit(EXIT_STATUS_ERROR);
        }
    }

#ifdef WITH_PGP
  if (pgp_keyring[0] != '/')
    {
      char buf[1024];
      snprintf(buf, sizeof (buf), "%s/%s/%s", 
               ssh_user_dir(user), 
               SSH_USER_DIR,
               pgp_keyring);
      ssh_xfree(pgp_keyring);
      pgp_keyring = ssh_xstrdup(buf);
    }
#endif /* WITH_PGP */

  files = &av[ssh_optind];
  num_files = ac - ssh_optind;

  /* Fetch default from ~/.ssh2/id_* (the first that we happen to get) */

#define ID_PREFIX "id"
  
  if (num_files == 0 && action != LIST && action != DELETE_ALL &&
      action != LOCK && action != UNLOCK)
    {
#ifdef WITH_PGP
      if (pgp_mode != PGP_KEY_NONE)
        {
          fprintf(stderr, "%s: Nothing to do!\n",  av0);
          exit(EXIT_STATUS_ERROR);
        }
#endif /* WITH_PGP */
      ssh_dsprintf(&ssh2dirname, "%s/%s", ssh_user_dir(user), SSH_USER_DIR);
      ssh2dir = opendir(ssh2dirname);

      if (!ssh2dir)
        {
          fprintf(stderr, "%s: Can't open directory \"%s\"", av0, ssh2dirname);
          exit(EXIT_STATUS_ERROR);
        }
          
      while ((cand = readdir(ssh2dir)) != NULL)
        {
          if ((strlen(cand->d_name) > strlen(ID_PREFIX)) &&
              (strncmp(cand->d_name, ID_PREFIX, strlen(ID_PREFIX)) == 0) &&
              ((strlen(cand->d_name) < 4) ||
               (strcmp(cand->d_name + strlen(cand->d_name) - 4,
                       ".pub") != 0)) &&
              ((((cand->d_name)[strlen(ID_PREFIX)]) == '_') ||
               (((cand->d_name)[strlen(ID_PREFIX)]) == '-') ||
               (((cand->d_name)[strlen(ID_PREFIX)]) == '.') ||
               (((cand->d_name)[strlen(ID_PREFIX)]) == '(') ||
               (((cand->d_name)[strlen(ID_PREFIX)]) == '[') ||
               (((cand->d_name)[strlen(ID_PREFIX)]) == '<') ||
               (((cand->d_name)[strlen(ID_PREFIX)]) == '>')))
            {
              files = ssh_xcalloc(2, sizeof(char *));
              ssh_dsprintf(&files[0], "%s/%s", ssh2dirname, cand->d_name);
              ssh_xfree(ssh2dirname);
              num_files++;
              dynamic_array = TRUE;
              break;
            }
        }
      (void)closedir(ssh2dir);
    }
  
  signal(SIGPIPE, SIG_IGN);
  
  ssh_event_loop_initialize();
  
  ssh_agent_open(agent_open_callback, NULL);

  ssh_event_loop_run();
  ssh_event_loop_uninitialize();

  if (dynamic_array)
    {
      for(i = 0; i < num_files ; i++)
        {
          ssh_xfree(files[i]);
        }
      ssh_xfree(files);
    }
  
  ssh_user_free(user, FALSE);
  exit(EXIT_STATUS_OK);
}