Esempio n. 1
0
/**Parse HTTP query string.
 *
 * The function http_query_parse() searches for the given keys in HTTP @a
 * query. For each key, a query element (in the form name=value) is searched
 * from the query string. If a query element has a beginning matching with
 * the key, a copy of the rest of the element is returned in corresponding
 * return_value argument.
 *
 * @note The @a query string will be modified.
 *
 * @return
 * The function http_query_parse() returns number keys that matched within
 * the @a query string.
 */
issize_t http_query_parse(char *query,
			  /* char const *key, char **return_value, */
			  ...)
{
  va_list ap;
  char *q, *q_next;
  char *name, *value, **return_value;
  char const *key;
  size_t namelen, valuelen, keylen;
  isize_t N;
  int has_value;

  if (!query)
    return -1;

  for (q = query, N = 0; *q; q = q_next) {
    namelen = strcspn(q, "=&");
    valuelen = namelen + strcspn(q + namelen, "&");

    q_next = q + valuelen;
    if (*q_next)
      *q_next++ = '\0';

    value = q + namelen;
    has_value = (*value) != '\0'; /* is the part in form of name=value? */
    if (has_value)
      *value++ = '\0';

    name = url_unescape(q, q);

    if (has_value) {
      namelen = strlen(name);
      name[namelen] = '=';
      url_unescape(name + namelen + 1, value);
    }

    va_start(ap, query);

    while ((key = va_arg(ap, char const *))) {
      return_value = va_arg(ap, char **);
      keylen = strlen(key);

      if (strncmp(key, name, keylen) == 0) {
	*return_value = name + keylen;
	N++;
      }
    }

    va_end(ap);
  }

  return N;
}
Esempio n. 2
0
int main(int argc, char *argv[])
{
    int fd;
    char name[64], *buf, *out = NULL, *verify;
    size_t len, outlen;
    buf = get_file_buffer(argv[1], &len);
    if (buf) {
        if (argc > 2) {
            if (url_unescape(buf, len, &out, &outlen) == 0) {
                printf("%.*s\n", (int)outlen, out);
                if ((verify = url_escape(out, outlen))) {
                    fd = get_tmpfile(name, 0666, NULL, NULL);
                    if (fd > 0) {
                        printf("verify file:%s\n", name);
                        write(fd, verify, strlen(verify));
                        close(fd);
                    }
                }
            }
        } else {
            if ((out = url_escape(buf, len)))
                printf("%s\n", out);
        }
        free(buf);
        if (out) free(out);
    }
}
Esempio n. 3
0
/**
 * Create a path from a nsurl using amiga file handling.
 *
 * @param[in] url The url to encode.
 * @param[out] path_out A string containing the result path which should
 *                      be freed by the caller.
 * @return NSERROR_OK and the path is written to \a path or error code
 *         on faliure.
 */
static nserror amiga_nsurl_to_path(struct nsurl *url, char **path_out)
{
	lwc_string *urlpath;
	char *path;
	bool match;
	lwc_string *scheme;
	nserror res;
	char *colon;
	char *slash;

	if ((url == NULL) || (path_out == NULL)) {
		return NSERROR_BAD_PARAMETER;
	}

	scheme = nsurl_get_component(url, NSURL_SCHEME);

	if (lwc_string_caseless_isequal(scheme, corestring_lwc_file,
					&match) != lwc_error_ok)
	{
		return NSERROR_BAD_PARAMETER;
	}
	lwc_string_unref(scheme);
	if (match == false) {
		return NSERROR_BAD_PARAMETER;
	}

	urlpath = nsurl_get_component(url, NSURL_PATH);
	if (urlpath == NULL) {
		return NSERROR_BAD_PARAMETER;
	}

	res = url_unescape(lwc_string_data(urlpath) + 1, &path);
	lwc_string_unref(urlpath);
	if (res != NSERROR_OK) {
		return res;
	}

	colon = strchr(path, ':');
	if(colon == NULL)
	{
		slash = strchr(path, '/');
		if(slash)
		{
			*slash = ':';
		}
		else
		{
			int len = strlen(path);
			path[len] = ':';
			path[len + 1] = '\0';
		}
	}

	*path_out = path;

	return NSERROR_OK;
}
Esempio n. 4
0
static char *url_to_path(const char *url)
{
	char *url_path;
	char *path = NULL;

	if (url_unescape(url, 0, &url_path) == NSERROR_OK) {
		/* return the absolute path including leading / */
		path = strdup(url_path + (FILE_SCHEME_PREFIX_LEN - 1));
		free(url_path);
	}

	return path;
}
Esempio n. 5
0
/**
 * Try and find the correct RISC OS filetype from a download context.
 */
static nserror download_ro_filetype(download_context *ctx, bits *ftype_out)
{
	nsurl *url = download_context_get_url(ctx);
	bits ftype = 0;
	lwc_string *scheme;

	/* If the file is local try and read its filetype */
	scheme = nsurl_get_component(url, NSURL_SCHEME);
	if (scheme != NULL) {
		bool filescheme;
		if (lwc_string_isequal(scheme,
				       corestring_lwc_file,
				       &filescheme) != lwc_error_ok) {
			filescheme = false;
		}

		if (filescheme) {
			lwc_string *path = nsurl_get_component(url, NSURL_PATH);
			if (path != NULL && lwc_string_length(path) != 0) {
				char *raw_path;
				if (url_unescape(lwc_string_data(path),
						 lwc_string_length(path),
						 &raw_path) == NSERROR_OK) {
					ftype =	ro_filetype_from_unix_path(raw_path);
					free(raw_path);
				}
			}
		}
	}

	/* If we still don't have a filetype (i.e. failed reading local
	 * one or fetching a remote object), then use the MIME type.
	 */
	if (ftype == 0) {
		/* convert MIME type to RISC OS file type */
		os_error *error;
		const char *mime_type;

		mime_type = download_context_get_mime_type(ctx);
		error = xmimemaptranslate_mime_type_to_filetype(mime_type, &ftype);
		if (error) {
			LOG("xmimemaptranslate_mime_type_to_filetype: 0x%x: %s", error->errnum, error->errmess);
			ro_warn_user("MiscError", error->errmess);
			ftype = 0xffd;
		}
	}

	*ftype_out = ftype;
	return NSERROR_OK;
}
Esempio n. 6
0
char *url_to_path(const char *url)
{
	char *path;
	char *respath;
	url_func_result res; /* result from url routines */

	res = url_path(url, &path);
	if (res != URL_FUNC_OK) {
		return NULL;
	}

	res = url_unescape(path, &respath);
	free(path);
	if (res != URL_FUNC_OK) {
		return NULL;
	}

	return respath;
}
Esempio n. 7
0
int
url_2char_canonical (url_t * url, char **dest)
{
  int result;
  *dest = NULL;
  result = url_2char (url, dest);
  if (result == 0)
    {
      /*
         tmp = strchr(*dest, ";");
         if (tmp !=NULL) {
         buf=strndup(*dest, tmp-(*dest));
         sfree(*dest);
         *dest=buf;
         }
       */
      url_unescape (*dest);
    }
  return result;
}
Esempio n. 8
0
char *url_to_path(const char *url)
{
	char *unesc, *slash, *colon, *url2;

	if (strncmp(url, "file://", SLEN("file://")) != 0)
		return NULL;

	url += SLEN("file://");

	if (strncmp(url, "localhost", SLEN("localhost")) == 0)
		url += SLEN("localhost");

	if (strncmp(url, "/", SLEN("/")) == 0)
		url += SLEN("/");

	if(*url == '\0')
		return NULL; /* file:/// is not a valid path */

	url2 = malloc(strlen(url) + 2);
	strcpy(url2, url);

	colon = strchr(url2, ':');
	if(colon == NULL)
	{
		if(slash = strchr(url2, '/'))
		{
			*slash = ':';
		}
		else
		{
			int len = strlen(url2);
			url2[len] = ':';
			url2[len + 1] = '\0';
		}
	}

	if(url_unescape(url2,&unesc) == URL_FUNC_OK)
		return unesc;

	return (char *)url2;
}
Esempio n. 9
0
struct magnet_resource * 
magnet_parse(const char *url, const char **error_str)
{
	static const struct magnet_resource zero_resource;
	struct magnet_resource res;
	const char *p, *next;

	res = zero_resource;
	clear_error_str(&error_str);

	p = is_strcaseprefix(url, "magnet:");
	if (!p) {
		*error_str = "Not a MAGNET URI";
		return NULL;
	}

	if ('?' != p[0]) {
		*error_str = "Invalid MAGNET URI";
		return NULL;
	}
	p++;

	for (/* NOTHING */; p && '\0' != p[0]; p = next) {
		enum magnet_key key;
		const char *endptr;
		char name[16]; /* Large enough to hold longest key we know */

		name[0] = '\0';
		endptr = strchr(p, '=');
		if (endptr && p != endptr) {
			size_t name_len;

			name_len = endptr - p;
			g_assert(size_is_positive(name_len));

			if (name_len < sizeof name) {  /* Ignore overlong key */
				strncat(name, p, name_len);
			}
			p = &endptr[1]; /* Point behind the '=' */
		}

		endptr = strchr(p, '&');
		if (!endptr) {
			endptr = strchr(p, '\0');
		}

		key = magnet_key_get(name);
		if (MAGNET_KEY_NONE == key) {
			g_message("skipping unknown key \"%s\" in MAGNET URI", name);
		} else {
			char *value;
			size_t value_len;

			value_len = endptr - p;
			value = h_strndup(p, value_len);

			plus_to_space(value);
			if (url_unescape(value, TRUE)) {
				magnet_handle_key(&res, name, value);
			} else {
				g_message("badly encoded value in MAGNET URI: \"%s\"", value);
			}
			HFREE_NULL(value);
		}

		while ('&' == endptr[0]) {
			endptr++;
		}
		next = endptr;
	}

	res.sources = g_slist_reverse(res.sources);
	res.searches = g_slist_reverse(res.searches);

	return wcopy(&res, sizeof res);
}
Esempio n. 10
0
static bool fetch_data_process(struct fetch_data_context *c)
{
	nserror res;
	fetch_msg msg;
	char *params;
	char *comma;
	char *unescaped;
	size_t unescaped_len;
	
	/* format of a data: URL is:
	 *   data:[<mimetype>][;base64],<data>
	 * The mimetype is optional.  If it is missing, the , before the
	 * data must still be there.
	 */
	
	NSLOG(netsurf, INFO, "url: %.140s", c->url);
	
	if (strlen(c->url) < 6) {
		/* 6 is the minimum possible length (data:,) */
		msg.type = FETCH_ERROR;
		msg.data.error = "Malformed data: URL";
		fetch_data_send_callback(&msg, c);
		return false;
	}
	
	/* skip the data: part */
	params = c->url + SLEN("data:");
	
	/* find the comma */
	if ( (comma = strchr(params, ',')) == NULL) {
		msg.type = FETCH_ERROR;
		msg.data.error = "Malformed data: URL";
		fetch_data_send_callback(&msg, c);
		return false;
	}
	
	if (params[0] == ',') {
		/* there is no mimetype here, assume text/plain */
		c->mimetype = strdup("text/plain;charset=US-ASCII");
	} else {	
		/* make a copy of everything between data: and the comma */
		c->mimetype = strndup(params, comma - params);
	}
	
	if (c->mimetype == NULL) {
		msg.type = FETCH_ERROR;
		msg.data.error = 
			"Unable to allocate memory for mimetype in data: URL";
		fetch_data_send_callback(&msg, c);
		return false;
	}
	
	if (strcmp(c->mimetype + strlen(c->mimetype) - 7, ";base64") == 0) {
		c->base64 = true;
		c->mimetype[strlen(c->mimetype) - 7] = '\0';
	} else {
		c->base64 = false;
	}
	
	/* URL unescape the data first, just incase some insane page
	 * decides to nest URL and base64 encoding.  Like, say, Acid2.
	 */
	res = url_unescape(comma + 1, 0, &unescaped_len, &unescaped);
	if (res != NSERROR_OK) {
		msg.type = FETCH_ERROR;
		msg.data.error = "Unable to URL decode data: URL";
		fetch_data_send_callback(&msg, c);
		return false;
	}
	
	if (c->base64) {
		if ((nsu_base64_decode_alloc((uint8_t *)unescaped,
					     unescaped_len,
					     (uint8_t **)&c->data,
					     &c->datalen) != NSUERROR_OK) ||
		    (c->data == NULL)) {
			msg.type = FETCH_ERROR;
			msg.data.error = "Unable to Base64 decode data: URL";
			fetch_data_send_callback(&msg, c);
			free(unescaped);
			return false;
		}
	} else {
		c->data = malloc(unescaped_len);
		if (c->data == NULL) {
			msg.type = FETCH_ERROR;
			msg.data.error =
				"Unable to allocate memory for data: URL";
			fetch_data_send_callback(&msg, c);
			free(unescaped);
			return false;
		}
		c->datalen = unescaped_len;
		memcpy(c->data, unescaped, unescaped_len);
	}
	
	free(unescaped);
	
	return true;
}
Esempio n. 11
0
int
url_parse_params (url_t * url, char *params)
{
  char *pname;
  char *pvalue;

  char *comma;
  char *equal;

  /* find '=' wich is the separator for one param */
  /* find ';' wich is the separator for multiple params */

  equal = next_separator (params + 1, '=', ';');
  comma = strchr (params + 1, ';');

  while (comma != NULL)
    {
      if (equal == NULL)
	{
	  equal = comma;
	  pvalue = NULL;
	}
      else
	{
	  if (comma - equal < 2)
	    return -1;
	  pvalue = (char *) smalloc (comma - equal);
	  if (pvalue == NULL)
	    return -1;
	  sstrncpy (pvalue, equal + 1, comma - equal - 1);
	  url_unescape (pvalue);
	}

      if (equal - params < 2)
	{
	  sfree (pvalue);
	  return -1;
	}
      pname = (char *) smalloc (equal - params);
      if (pname == NULL)
	{
	  sfree (pvalue);
	  return -1;
	}
      sstrncpy (pname, params + 1, equal - params - 1);
      url_unescape (pname);

      url_uparam_add (url, pname, pvalue);

      params = comma;
      equal = next_separator (params + 1, '=', ';');
      comma = strchr (params + 1, ';');
    }

  /* this is the last header (comma==NULL) */
  comma = params + strlen (params);

  if (equal == NULL)
    {
      equal = comma;		/* at the end */
      pvalue = NULL;
    }
  else
    {
      if (comma - equal < 2)
	return -1;
      pvalue = (char *) smalloc (comma - equal);
      if (pvalue == NULL)
	return -1;
      sstrncpy (pvalue, equal + 1, comma - equal - 1);
    }

  if (equal - params < 2)
    {
      sfree (pvalue);
      return -1;
    }
  pname = (char *) smalloc (equal - params);
  if (pname == NULL)
    {
      sfree (pvalue);
      return -1;
    }
  sstrncpy (pname, params + 1, equal - params - 1);

  url_uparam_add (url, pname, pvalue);

  return 0;
}
Esempio n. 12
0
int
url_parse_headers (url_t * url, char *headers)
{
  char *and;
  char *equal;

  /* find '=' wich is the separator for one header */
  /* find ';' wich is the separator for multiple headers */

  equal = strchr (headers, '=');
  and = strchr (headers + 1, '&');

  if (equal == NULL)		/* each header MUST have a value */
    return -1;

  do
    {
      char *hname;
      char *hvalue;

      hname = (char *) smalloc (equal - headers);
      if (hname == NULL)
	return -1;
      sstrncpy (hname, headers + 1, equal - headers - 1);
      url_unescape (hname);

      if (and != NULL)
	{
	  if (and - equal < 2)
	    {
	      sfree (hname);
	      return -1;
	    }
	  hvalue = (char *) smalloc (and - equal);
	  if (hvalue == NULL)
	    {
	      sfree (hname);
	      return -1;
	    }
	  sstrncpy (hvalue, equal + 1, and - equal - 1);
	  url_unescape (hvalue);
	}
      else
	{			/* this is for the last header (no and...) */
	  if (headers + strlen (headers) - equal + 1 < 2)
	    {
	      sfree (hname);
	      return -1;
	    }
	  hvalue = (char *) smalloc (headers + strlen (headers) - equal + 1);
	  if (hvalue == NULL)
	    {
	      sfree (hname);
	      return -1;
	    }
	  sstrncpy (hvalue, equal + 1, headers + strlen (headers) - equal);
	  url_unescape (hvalue);
	}

      url_uheader_add (url, hname, hvalue);

      if (and == NULL)		/* we just set the last header */
	equal = NULL;
      else			/* continue on next header */
	{
	  headers = and;
	  equal = strchr (headers, '=');
	  and = strchr (headers + 1, '&');
	  if (equal == NULL)	/* each header MUST have a value */
	    return -1;
	}
    }
  while (equal != NULL);
  return 0;
}
Esempio n. 13
0
/* return -1 on error */
int
url_parse (url_t * url, char *buf)
{
  char *username;
  char *password;
  char *host;
  char *port;
  char *params;
  char *headers;
  char *tmp;

  /* basic tests */
  if (buf == NULL)
    return -1;

  tmp = strchr (buf, ':');
  if (tmp == NULL)
    return -1;

  if (tmp - buf < 2)
    return -1;
  url->scheme = (char *) smalloc (tmp - buf + 1);
  if (url->scheme == NULL)
    return -1;
  sstrncpy (url->scheme, buf, tmp - buf);

#if (!defined WIN32 && !defined _WIN32_WCE)
  if (strlen (url->scheme) < 3 ||
      (0 != strncasecmp (url->scheme, "sip", 3)
       && 0 != strncasecmp (url->scheme, "sips", 4)))
    {				/* Is not a sipurl ! */
      int i = strlen (tmp + 1);

      if (i < 2)
	return -1;
      url->string = (char *) smalloc (i + 1);
      if (url->string == NULL)
	return -1;
      sstrncpy (url->string, tmp + 1, i);
      return 0;
    }
#else
  if (strlen (url->scheme) < 3 ||
      (0 != _strnicmp (url->scheme, "sip", 3)
       && 0 != _strnicmp (url->scheme, "sips", 4)))
    {				/* Is not a sipurl ! */
      int i = strlen (tmp + 1);

      if (i < 2)
	return -1;
      url->string = (char *) smalloc (i + 1);
      if (url->string == NULL)
	return -1;
      sstrncpy (url->string, tmp + 1, i);
      return 0;
    }
#endif

  /*  law number 1:
     if ('?' exists && is_located_after '@')
     or   if ('?' exists && '@' is not there -no username-)
     =====>  HEADER_PARAM EXIST
     =====>  start at index(?)
     =====>  end at the end of url
   */

  /* find the beginning of host */
  username = strchr (buf, ':');
  /* if ':' does not exist, the url is not valid */
  if (username == NULL)
    return -1;

  host = strchr (buf, '@');

  if (host == NULL)
    host = username;
  else
    /* username exists */
    {
      password = next_separator (username + 1, ':', '@');
      if (password == NULL)
	password = host;
      else
	/* password exists */
	{
	  if (host - password < 2)
	    return -1;
	  url->password = (char *) smalloc (host - password);
	  if (url->password == NULL)
	    return -1;
	  sstrncpy (url->password, password + 1, host - password - 1);
	  url_unescape (url->password);
	}
      if (password - username < 2)
	return -1;
      {
	url->username = (char *) smalloc (password - username);
	if (url->username == NULL)
	  return -1;
	sstrncpy (url->username, username + 1, password - username - 1);
	url_unescape (url->username);
      }
    }


  /* search for header after host */
  headers = strchr (host, '?');

  if (headers == NULL)
    headers = buf + strlen (buf);
  else
    /* headers exist */
    url_parse_headers (url, headers);


  /* search for params after host */
  params = strchr (host, ';');	/* search for params after host */
  if (params == NULL)
    params = headers;
  else
    /* params exist */
    {
      if (headers - params + 1 < 2)
	return -1;
      tmp = smalloc (headers - params + 1);
      if (tmp == NULL)
	return -1;
      tmp = sstrncpy (tmp, params, headers - params);
      url_parse_params (url, tmp);
      sfree (tmp);
    }

  port = params - 1;
  while (port > host && *port != ']' && *port != ':')
    port--;
  if (*port == ':')
    {
      if (host == port)
	port = params;
      else
	{
	  if ((params - port < 2) || (params - port > 8))
	    return -1;		/* error cases */
	  url->port = (char *) smalloc (params - port);
	  if (url->port == NULL)
	    return -1;
	  sstrncpy (url->port, port + 1, params - port - 1);
	  sclrspace (url->port);
	}
    }
  else
    port = params;
  /* adjust port for ipv6 address */
  tmp = port;
  while (tmp > host && *tmp != ']')
    tmp--;
  if (*tmp == ']')
    {
      port = tmp;
      while (host < port && *host != '[')
	host++;
      if (host >= port)
	return -1;
    }

  if (port - host < 2)
    return -1;
  url->host = (char *) smalloc (port - host);
  if (url->host == NULL)
    return -1;
  sstrncpy (url->host, host + 1, port - host - 1);
  sclrspace (url->host);

  return 0;
}
Esempio n. 14
0
G_GNUC_COLD void
upload_stats_load_history(void)
{
	FILE *upload_stats_file;
	file_path_t fp;
	char line[FILENAME_MAX + 64];
	guint lineno = 0;

	gcu_upload_stats_gui_freeze();
	
	file_path_set(&fp, settings_config_dir(), ul_stats_file);

	/* open file for reading */
	upload_stats_file = file_config_open_read(ul_stats_what, &fp, 1);
	if (upload_stats_file == NULL)
		goto done;

	/* parse, insert names into ul_stats_clist */
	while (fgets(line, sizeof(line), upload_stats_file)) {
		static const struct ul_stats zero_item;
		struct ul_stats item;
		struct sha1 sha1_buf;
		const char *p;
		size_t i;

		lineno++;
		if (line[0] == '#' || line[0] == '\n')
			continue;

		p = strchr(line, '\t');
		if (NULL == p)
			goto corrupted;

		line[p - line] = '\0';		/* line is now the URL-escaped file name */
		p++;

		/* URL-unescape in-place */
		if (!url_unescape(line, TRUE))
			goto corrupted;

		item = zero_item;
		item.pathname = line;

		for (i = 0; i < 8; i++) {
			guint64 v;
			int error;
			const char *endptr;

			p = skip_ascii_spaces(p);

			/* SVN versions up to 15322 had only 6 fields in the history */
			if (5 == i && '\0' == *p)
				break;

			switch (i) {
			case 7:
				/* We have a SHA1 or '*' if none known */
				if ('*' != *p) {
					size_t len = clamp_strlen(p, SHA1_BASE32_SIZE);
					
					error = !parse_base32_sha1(p, len, &sha1_buf);
					item.sha1 = error ? NULL : &sha1_buf;
				} else {
					error = FALSE;
				}
				p = skip_ascii_non_spaces(p);
				v = 0;
				break;
			default:
				v = parse_uint64(p, &endptr, 10, &error);
				p = deconstify_gchar(endptr);
			}

			if (error || !is_ascii_space(*endptr))
				goto corrupted;

			switch (i) {
			case 0: item.size = v; break;
			case 1: item.attempts = v; break;
			case 2: item.complete = v; break;
			case 3: item.bytes_sent |= ((guint64) (guint32) v) << 32; break;
			case 4: item.bytes_sent |= (guint32) v; break;
			case 5: item.rtime = MIN(v + (time_t) 0, TIME_T_MAX + (guint64) 0);
			case 6: item.dtime = MIN(v + (time_t) 0, TIME_T_MAX + (guint64) 0); 
			case 7: break;	/* Already stored above */
			default:
				g_assert_not_reached();
				goto corrupted;
			}
		}

		/* 
		 * We store the filenames UTF-8 encoded but the file might have been
		 * edited or corrupted.
		 */
		if (is_absolute_path(item.pathname)) {
			item.filename = lazy_filename_to_utf8_normalized(
						filepath_basename(item.pathname), UNI_NORM_NFC);
		} else {
			item.filename = lazy_unknown_to_utf8_normalized(
						filepath_basename(item.pathname), UNI_NORM_NFC, NULL);
		}

		if (upload_stats_find(NULL, item.pathname, item.size)) {
			g_warning("upload_stats_load_history():"
				" Ignoring line %u due to duplicate file.", lineno);
		} else if (upload_stats_find(item.sha1, item.pathname, item.size)) {
			g_warning("upload_stats_load_history():"
				" Ignoring line %u due to duplicate file.", lineno);
		} else {
			upload_stats_add(item.pathname, item.size, item.filename,
				item.attempts, item.complete, item.bytes_sent,
				item.rtime, item.dtime, item.sha1);
		}
		continue;

	corrupted:
		g_warning("upload statistics file corrupted at line %u.", lineno);
	}

	/* close file */
	fclose(upload_stats_file);

done:
	gcu_upload_stats_gui_thaw();
	return;
}
Esempio n. 15
0
/**
 * Open a TFTP connection to the server
 *
 * @param:inode, the inode to store our state in
 * @param:ip, the ip to contact to get the file
 * @param:filename, the file we wanna open
 *
 * @out: open_file_t structure, stores in file->open_file
 * @out: the lenght of this file, stores in file->file_len
 *
 */
void tftp_open(struct url_info *url, int flags, struct inode *inode,
               const char **redir)
{
    struct pxe_pvt_inode *socket = PVT(inode);
    char *buf;
    uint16_t buf_len;
    char *p;
    char *options;
    char *data;
    static const char rrq_tail[] = "octet\0""tsize\0""0\0""blksize\0""1408";
    char rrq_packet_buf[2+2*FILENAME_MAX+sizeof rrq_tail];
    char reply_packet_buf[PKTBUF_SIZE];
    int err;
    int buffersize;
    int rrq_len;
    const uint8_t  *timeout_ptr;
    jiffies_t timeout;
    jiffies_t oldtime;
    uint16_t opcode;
    uint16_t blk_num;
    uint64_t opdata;
    uint16_t src_port;
    uint32_t src_ip;

    (void)redir;		/* TFTP does not redirect */
    (void)flags;

    if (url->type != URL_OLD_TFTP) {
        /*
         * The TFTP URL specification allows the TFTP to end with a
         * ;mode= which we just ignore.
         */
        url_unescape(url->path, ';');
    }

    if (!url->port)
        url->port = TFTP_PORT;

    socket->ops = &tftp_conn_ops;
    if (core_udp_open(socket))
        return;

    buf = rrq_packet_buf;
    *(uint16_t *)buf = TFTP_RRQ;  /* TFTP opcode */
    buf += 2;

    buf = stpcpy(buf, url->path);

    buf++;			/* Point *past* the final NULL */
    memcpy(buf, rrq_tail, sizeof rrq_tail);
    buf += sizeof rrq_tail;

    rrq_len = buf - rrq_packet_buf;

    timeout_ptr = TimeoutTable;   /* Reset timeout */
sendreq:
    timeout = *timeout_ptr++;
    if (!timeout)
        return;			/* No file available... */
    oldtime = jiffies();

    core_udp_sendto(socket, rrq_packet_buf, rrq_len, url->ip, url->port);

    /* If the WRITE call fails, we let the timeout take care of it... */
wait_pkt:
    for (;;) {
        buf_len = sizeof(reply_packet_buf);

        err = core_udp_recv(socket, reply_packet_buf, &buf_len,
                            &src_ip, &src_port);
        if (err) {
            jiffies_t now = jiffies();
            if (now - oldtime >= timeout)
                goto sendreq;
        } else {
            /* Make sure the packet actually came from the server and
               is long enough for a TFTP opcode */
            dprintf("tftp_open: got packet buflen=%d from server %u.%u.%u.%u(%u.%u.%u.%u)\n",
                    buf_len,
                    ((uint8_t *)&src_ip)[0],
                    ((uint8_t *)&src_ip)[1],
                    ((uint8_t *)&src_ip)[2],
                    ((uint8_t *)&src_ip)[3],
                    ((uint8_t *)&url->ip)[0],
                    ((uint8_t *)&url->ip)[1],
                    ((uint8_t *)&url->ip)[2],
                    ((uint8_t *)&url->ip)[3]);
            if ((src_ip == url->ip) && (buf_len >= 2))
                break;
        }
    }

    core_udp_disconnect(socket);
    core_udp_connect(socket, src_ip, src_port);

    /* filesize <- -1 == unknown */
    inode->size = -1;
    socket->tftp_blksize = TFTP_BLOCKSIZE;
    buffersize = buf_len - 2;	  /* bytes after opcode */

    /*
     * Get the opcode type, and parse it
     */
    opcode = *(uint16_t *)reply_packet_buf;
    switch (opcode) {
    case TFTP_ERROR:
        inode->size = 0;
        goto done;        /* ERROR reply; don't try again */

    case TFTP_DATA:
        /*
         * If the server doesn't support any options, we'll get a
         * DATA reply instead of OACK. Stash the data in the file
         * buffer and go with the default value for all options...
         *
         * We got a DATA packet, meaning no options are
         * suported. Save the data away and consider the
         * length undefined, *unless* this is the only
         * data packet...
         */
        buffersize -= 2;
        if (buffersize < 0)
            goto wait_pkt;
        data = reply_packet_buf + 2;
        blk_num = ntohs(*(uint16_t *)data);
        data += 2;
        if (blk_num != 1)
            goto wait_pkt;
        socket->tftp_lastpkt = blk_num;
        if (buffersize > TFTP_BLOCKSIZE)
            goto err_reply;	/* Corrupt */

        socket->tftp_pktbuf = malloc(TFTP_BLOCKSIZE + 4);
        if (!socket->tftp_pktbuf)
            goto err_reply;	/* Internal error */

        if (buffersize < TFTP_BLOCKSIZE) {
            /*
             * This is the final EOF packet, already...
             * We know the filesize, but we also want to
             * ack the packet and set the EOF flag.
             */
            inode->size = buffersize;
            socket->tftp_goteof = 1;
            ack_packet(inode, blk_num);
        }

        socket->tftp_bytesleft = buffersize;
        socket->tftp_dataptr = socket->tftp_pktbuf;
        memcpy(socket->tftp_pktbuf, data, buffersize);
        goto done;

    case TFTP_OACK:
        /*
         * Now we need to parse the OACK packet to get the transfer
         * and packet sizes.
         */

        options = reply_packet_buf + 2;
        p = options;

        while (buffersize) {
            const char *opt = p;

            /*
             * If we find an option which starts with a NUL byte,
             * (a null option), we're either seeing garbage that some
             * TFTP servers add to the end of the packet, or we have
             * no clue how to parse the rest of the packet (what is
             * an option name and what is a value?)  In either case,
             * discard the rest.
             */
            if (!*opt)
                goto done;

            while (buffersize) {
                if (!*p)
                    break;	/* Found a final null */
                *p++ |= 0x20;
                buffersize--;
            }
            if (!buffersize)
                break;		/* Unterminated option */

            /* Consume the terminal null */
            p++;
            buffersize--;

            if (!buffersize)
                break;		/* No option data */

            opdata = 0;

            /* do convert a number-string to decimal number, just like atoi */
            while (buffersize--) {
                uint8_t d = *p++;
                if (d == '\0')
                    break;              /* found a final null */
                d -= '0';
                if (d > 9)
                    goto err_reply;     /* Not a decimal digit */
                opdata = opdata*10 + d;
            }

            if (!strcmp(opt, "tsize"))
                inode->size = opdata;
            else if (!strcmp(opt, "blksize"))
                socket->tftp_blksize = opdata;
            else
                goto err_reply; /* Non-negotitated option returned,
				   no idea what it means ...*/


        }

        if (socket->tftp_blksize < 64 || socket->tftp_blksize > PKTBUF_SIZE)
            goto err_reply;

        /* Parsing successful, allocate buffer */
        socket->tftp_pktbuf = malloc(socket->tftp_blksize + 4);
        if (!socket->tftp_pktbuf)
            goto err_reply;
        else
            goto done;

    default:
        printf("TFTP unknown opcode %d\n", ntohs(opcode));
        goto err_reply;
    }

err_reply:
    /* Build the TFTP error packet */
    tftp_error(inode, TFTP_EOPTNEG, "TFTP protocol error");
    inode->size = 0;

done:
    if (!inode->size)
        core_udp_close(socket);

    return;
}
Esempio n. 16
0
/**
 * Send a file to a TFTP  server
 *
 * @param:inode, the inode to store our state in
 * @param:ip, the ip to contact to get the file
 * @param:filename, the file we wanna push
 *
 * @out: open_file_t structure, stores in file->open_file
 * @out: the lenght of this file, stores in file->file_len
 *
 */
__export int tftp_put(struct url_info *url, int flags, struct inode *inode,
                      const char **redir, char *data, int data_length)
{
    struct pxe_pvt_inode *socket = PVT(inode);
    char *buf;
    uint16_t buf_len;
    static const char wrq_tail[] = "octet";
    char wrq_packet_buf[512+4+6];
    char reply_packet_buf[PKTBUF_SIZE];
    int err;
    int wrq_len;
    const uint8_t  *timeout_ptr;
    jiffies_t timeout;
    jiffies_t oldtime;
    uint16_t opcode;
    uint16_t src_port = url->port;
    uint32_t src_ip;
    uint16_t seq = 0;
    size_t chunk = 0;
    int len = data_length;
    int return_code = -ntohs(TFTP_EUNDEF);

    (void)redir;		/* TFTP does not redirect */
    (void)flags;

    if (url->type != URL_OLD_TFTP) {
        /*
         * The TFTP URL specification allows the TFTP to end with a
         * ;mode= which we just ignore.
         */
        url_unescape(url->path, ';');
    }

    if (!src_port)
        src_port = TFTP_PORT;

//    socket->ops = &tftp_conn_ops;
    if (core_udp_open(socket))
        return return_code;

    buf = wrq_packet_buf;
    *(uint16_t *)buf = TFTP_WRQ;  /* TFTP opcode */
    buf += 2;

    buf += strlcpy(buf, url->path, 512);

    buf++;			/* Point *past* the final NULL */
    memcpy(buf, wrq_tail, sizeof wrq_tail);
    buf += sizeof wrq_tail;

    wrq_len = buf - wrq_packet_buf;

    timeout_ptr = TimeoutTable;   /* Reset timeout */
sendreq:
    timeout = *timeout_ptr++;
    if (!timeout)
        return return_code;			/* No file available... */
    oldtime = jiffies();

    core_udp_sendto(socket, wrq_packet_buf, wrq_len, url->ip, src_port);

    /* If the WRITE call fails, we let the timeout take care of it... */
    for (;;) {
        buf_len = sizeof(reply_packet_buf);

        err = core_udp_recv(socket, reply_packet_buf, &buf_len,
                            &src_ip, &src_port);
        if (err) {
            jiffies_t now = jiffies();
            if (now - oldtime >= timeout)
                goto sendreq;
        } else {
            /* Make sure the packet actually came from the server and
               is long enough for a TFTP opcode */
            dprintf("tftp_put: got packet buflen=%d from server %u.%u.%u.%u(%u.%u.%u.%u)\n",
                    buf_len,
                    ((uint8_t *)&src_ip)[0],
                    ((uint8_t *)&src_ip)[1],
                    ((uint8_t *)&src_ip)[2],
                    ((uint8_t *)&src_ip)[3],
                    ((uint8_t *)&url->ip)[0],
                    ((uint8_t *)&url->ip)[1],
                    ((uint8_t *)&url->ip)[2],
                    ((uint8_t *)&url->ip)[3]);
            if ((src_ip == url->ip) && (buf_len >= 2))
                break;
        }
    }

    core_udp_disconnect(socket);
    core_udp_connect(socket, src_ip, src_port);

    /* filesize <- -1 == unknown */
    inode->size = -1;
    socket->tftp_blksize = TFTP_BLOCKSIZE;

    /*
     * Get the opcode type, and parse it
     */
    opcode = *(uint16_t *)reply_packet_buf;
    switch (opcode) {
    case TFTP_ERROR:
        dprintf("tftp_push: received a TFTP_ERROR\n");
        struct tftp_error *te = (struct tftp_error *)(reply_packet_buf+1);
        return_code = -ntohs(te->errcode);
        inode->size = 0;
        goto done;        /* ERROR reply; don't try again */

    case TFTP_ACK:
        dprintf("tftp_push: received a TFTP_ACK\n");
        /* We received a ACK packet, sending the associated data packet */

        /* If data was completly sent, we can stop here */
        if (len == 0) {
            return_code = -ntohs(TFTP_OK);
            goto done;
        }

        /* If the server sequence is not aligned with our, we have an issue
         * Let's break the transmission for now but could be improved later */
        uint16_t srv_seq = ntohs(*(uint16_t *)(reply_packet_buf+2));
        if (srv_seq != seq) {
            printf("tftp_push: server sequence (%"PRIu16") is not aligned with our sequence (%"PRIu16"\n", srv_seq, seq);
            return_code = -ntohs(TFTP_EBADOP);
            goto done;
        }

        /* Let's transmit the data block */
        chunk = len >= 512 ? 512 : len;
        buf = wrq_packet_buf;
        *(uint16_t *)buf = TFTP_DATA;  /* TFTP opcode */
        *((uint16_t *)(buf+2)) = htons(++seq);
        memcpy(buf+4, data, chunk);
        wrq_len = chunk + 4;
        data += chunk;
        len -= chunk;
        timeout_ptr = TimeoutTable;   /* Reset timeout */
        goto sendreq;

    default:
        dprintf("tftp_push: unknown opcode %d\n", ntohs(opcode));
        return_code = -ntohs(TFTP_EOPTNEG);
        goto err_reply;
    }

err_reply:
    /* Build the TFTP error packet */
    dprintf("tftp_push: Failure\n");
    tftp_error(inode, TFTP_EOPTNEG, "TFTP protocol error");
    inode->size = 0;

done:
    if (!inode->size)
        core_udp_close(socket);

    return return_code;
}
Esempio n. 17
0
/* test unquoting and canonizing */
int test_quote(void)
{
  su_home_t home[1] = { SU_HOME_INIT(home) };
  url_t *u;
  char s[] = "%73ip:q%74est%01:%01%02%00@host%2enokia.com;%70aram=%01%02";
  char c[] = "sip:qtest%01:%01%02%[email protected];param=%01%02";
  char *d;

#define RESERVED        ";/?:@&=+$,"
#define DELIMS          "<>#%\""
#define UNWISE		"{}|\\^[]`"
#define EXCLUDED	RESERVED DELIMS UNWISE

  char escaped[1 + 3 * 23 + 1];

#define UNRESERVED    "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
                      "abcdefghijklmnopqrstuvwxyz" \
                      "0123456789" \
                      "-_.!~*'()"

  char unreserved[26 + 26 + 10 + 9 + 1];

  BEGIN();

  d = url_as_string(home, (url_t *)"sip:[email protected]");
  TEST_S(d, "sip:[email protected]");

  TEST(strlen(EXCLUDED), 23);
  TEST(strlen(UNRESERVED), 71);

  TEST_1(!url_reserved_p("foo"));
  TEST_1(!url_reserved_p(""));
  TEST_1(url_reserved_p("foobar:bar"));

  TEST_SIZE(url_esclen("a" EXCLUDED, ""),
	    1 + strlen(RESERVED) + 3 * strlen(DELIMS UNWISE));
  TEST_SIZE(url_esclen("a" EXCLUDED, DELIMS UNWISE),
	    1 + strlen(RESERVED) + 3 * strlen(DELIMS UNWISE));
  TEST_SIZE(url_esclen("a" EXCLUDED, EXCLUDED), 1 + 3 * strlen(EXCLUDED));
  TEST_SIZE(url_esclen("a" EXCLUDED, NULL), 1 + 3 * strlen(EXCLUDED));

  TEST_S(url_escape(escaped, "a" EXCLUDED, NULL),
	 "a%3B%2F%3F%3A%40%26%3D%2B%24%2C"
	 "%3C%3E%23%25%22"
	 "%7B%7D%7C%5C%5E%5B%5D%60");
  TEST_S(url_unescape(escaped, escaped), "a" EXCLUDED);

  TEST_SIZE(url_esclen(UNRESERVED, NULL), strlen(UNRESERVED));
  TEST_S(url_escape(unreserved, UNRESERVED, NULL), UNRESERVED);
  TEST_S(url_unescape(unreserved, UNRESERVED), UNRESERVED);

  d = "%53ip:%75@%48";		/* Sip:u@H */
  u = url_hdup(home, (url_t *)d); TEST_1(u);
  url_digest(hash1, sizeof(hash1), u, NULL);
  url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL);
  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);

  d = "sip:u@h";
  u = url_hdup(home, (url_t *)d); TEST_1(u);
  url_digest(hash1, sizeof(hash1), u, NULL);
  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);
  url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL);
  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);

  u = url_hdup(home, (url_t *)s); TEST_1(u);
  d = url_as_string(home, u); TEST_1(d);
  TEST_S(d, c);

  d = "sip:&=+$,;?/:&=+$,@[::1]:56001;param=+$,/:@&;another=@%40%2F"
    "?header=" RESERVED "&%3b%2f%3f%3a%40%26%3d%2b%24%2c";
  u = url_hdup(home, (url_t *)d); TEST_1(u);
  TEST_S(u->url_user, "&=+$,;?/");
  TEST_S(u->url_host, "[::1]");
  TEST_S(u->url_params, "param=+$,/:@&;another=@%40/");
  TEST_S(u->url_headers, "header=" RESERVED "&%3B%2F%3F%3A%40%26%3D%2B%24%2C");
  url_digest(hash1, sizeof(hash1), u, NULL);
  url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL);
  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);

  u = url_hdup(home, (url_t *)s); TEST_1(u);
  d = url_as_string(home, u); TEST_1(d);
  TEST_S(d, c);

  d = "http://&=+$,;:&=+$,;@host:8080/foo%2F%3B%3D"
    ";param=+$,%2f%3b%3d/bar;param=:@&;another=@"
    "?query=" RESERVED;
  u = url_hdup(home, (url_t *)d); TEST_1(u);
  TEST_S(u->url_user, "&=+$,;"); TEST_S(u->url_password, "&=+$,;");
  TEST_S(u->url_path, "foo%2F%3B%3D;param=+$,%2F%3B%3D/bar;param=:@&;another=@");
  url_digest(hash1, sizeof(hash1), u, NULL);
  url_digest(hash2, sizeof(hash2), (url_t const *)d, NULL);
  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);

  u = url_hdup(home, (url_t *)s); TEST_1(u);
  d = url_as_string(home, u); TEST_1(d);
  TEST_S(d, c);

  url_digest(hash1, sizeof(hash1), u, NULL);
  url_digest(hash2, sizeof(hash2), (url_t const *)s, NULL);
  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);

  url_digest(hash2, sizeof(hash2), (url_t const *)c, NULL);
  TEST(memcmp(hash1, hash2, sizeof(hash1)), 0);

  END();
}