Пример #1
0
grub_err_t
grub_archelp_open (struct grub_archelp_data *data,
		   struct grub_archelp_ops *arcops,
		   const char *name_in)
{
  char *fn;
  char *name = grub_strdup (name_in + 1);
  int symlinknest = 0;

  if (!name)
    return grub_errno;

  canonicalize (name);

  while (1)
    {
      grub_uint32_t mode;
      grub_int32_t mtime;
      int restart;
      
      if (arcops->find_file (data, &fn, &mtime, &mode))
	goto fail;

      if (mode == GRUB_ARCHELP_ATTR_END)
	{
	  grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), name_in);
	  break;
	}

      canonicalize (fn);

      if (handle_symlink (data, arcops, fn, &name, mode, &restart))
	{
	  grub_free (fn);
	  goto fail;
	}

      if (restart)
	{
	  arcops->rewind (data);
	  if (++symlinknest == 8)
	    {
	      grub_error (GRUB_ERR_SYMLINK_LOOP,
			  N_("too deep nesting of symlinks"));
	      goto fail;
	    }
	  goto no_match;
	}

      if (grub_strcmp (name, fn) != 0)
	goto no_match;

      grub_free (fn);
      grub_free (name);

      return GRUB_ERR_NONE;

    no_match:

      grub_free (fn);
    }

fail:
  grub_free (name);

  return grub_errno;
}
Пример #2
0
grub_err_t
grub_archelp_dir (struct grub_archelp_data *data,
		  struct grub_archelp_ops *arcops,
		  const char *path_in,
		  grub_fs_dir_hook_t hook, void *hook_data)
{
  char *prev, *name, *path, *ptr;
  grub_size_t len;
  int symlinknest = 0;

  path = grub_strdup (path_in + 1);
  if (!path)
    return grub_errno;
  canonicalize (path);
  for (ptr = path + grub_strlen (path) - 1; ptr >= path && *ptr == '/'; ptr--)
    *ptr = 0;

  prev = 0;

  len = grub_strlen (path);
  while (1)
    {
      grub_int32_t mtime;
      grub_uint32_t mode;
      grub_err_t err;

      if (arcops->find_file (data, &name, &mtime, &mode))
	goto fail;

      if (mode == GRUB_ARCHELP_ATTR_END)
	break;

      canonicalize (name);

      if (grub_memcmp (path, name, len) == 0
	  && (name[len] == 0 || name[len] == '/' || len == 0))
	{
	  char *p, *n;

	  n = name + len;
	  while (*n == '/')
	    n++;

	  p = grub_strchr (n, '/');
	  if (p)
	    *p = 0;

	  if (((!prev) || (grub_strcmp (prev, name) != 0)) && *n != 0)
	    {
	      struct grub_dirhook_info info;
	      grub_memset (&info, 0, sizeof (info));
	      info.dir = (p != NULL) || ((mode & GRUB_ARCHELP_ATTR_TYPE)
					 == GRUB_ARCHELP_ATTR_DIR);
	      info.symlink = (p != NULL) || ((mode & GRUB_ARCHELP_ATTR_TYPE)
					 == GRUB_ARCHELP_ATTR_LNK);
	      if (!(mode & GRUB_ARCHELP_ATTR_NOTIME))
		{
		  info.mtime = mtime;
		  info.mtimeset = 1;
		}
	      if (hook (n, &info, hook_data))
		{
		  grub_free (name);
		  goto fail;
		}
	      grub_free (prev);
	      prev = name;
	    }
	  else
	    {
	      int restart = 0;
	      err = handle_symlink (data, arcops, name,
				    &path, mode, &restart);
	      grub_free (name);
	      if (err)
		goto fail;
	      if (restart)
		{
		  len = grub_strlen (path);
		  if (++symlinknest == 8)
		    {
		      grub_error (GRUB_ERR_SYMLINK_LOOP,
				  N_("too deep nesting of symlinks"));
		      goto fail;
		    }
		  arcops->rewind (data);
		}
	    }
	}
      else
	grub_free (name);
    }

fail:

  grub_free (path);
  grub_free (prev);

  return grub_errno;
}
Пример #3
0
grub_err_t
grub_net_dns_lookup (const char *name,
		     const struct grub_net_network_level_address *servers,
		     grub_size_t n_servers,
		     grub_size_t *naddresses,
		     struct grub_net_network_level_address **addresses,
		     int cache)
{
  grub_size_t send_servers = 0;
  grub_size_t i, j;
  struct grub_net_buff *nb;
  grub_net_udp_socket_t sockets[n_servers];
  grub_uint8_t *optr;
  const char *iptr;
  struct dns_header *head;
  static grub_uint16_t id = 1;
  grub_err_t err = GRUB_ERR_NONE;
  struct recv_data data = {naddresses, addresses, cache,
			   grub_cpu_to_be16 (id++), 0, 0, name};
  grub_uint8_t *nbd;
  int have_server = 0;

  if (!servers)
    {
      servers = dns_servers;
      n_servers = dns_nservers;
    }

  if (!n_servers)
    return grub_error (GRUB_ERR_BAD_ARGUMENT,
		       N_("no DNS servers configured"));

  *naddresses = 0;
  if (cache)
    {
      int h;
      h = hash (name);
      if (dns_cache[h].name && grub_strcmp (dns_cache[h].name, name) == 0
	  && grub_get_time_ms () < dns_cache[h].limit_time)
	{
	  grub_dprintf ("dns", "retrieved from cache\n");
	  *addresses = grub_malloc (dns_cache[h].naddresses
				    * sizeof ((*addresses)[0]));
	  if (!*addresses)
	    return grub_errno;
	  *naddresses = dns_cache[h].naddresses;
	  grub_memcpy (*addresses, dns_cache[h].addresses,
		       dns_cache[h].naddresses
		       * sizeof ((*addresses)[0]));
	  return GRUB_ERR_NONE;
	}
    }

  data.name = grub_strdup (name);
  if (!data.name)
    return grub_errno;

  nb = grub_netbuff_alloc (GRUB_NET_OUR_MAX_IP_HEADER_SIZE
			   + GRUB_NET_MAX_LINK_HEADER_SIZE
			   + GRUB_NET_UDP_HEADER_SIZE
			   + sizeof (struct dns_header)
			   + grub_strlen (name) + 2 + 4
			   + 2 + 4);
  if (!nb)
    {
      grub_free (data.name);
      return grub_errno;
    }
  grub_netbuff_reserve (nb, GRUB_NET_OUR_MAX_IP_HEADER_SIZE
			+ GRUB_NET_MAX_LINK_HEADER_SIZE
			+ GRUB_NET_UDP_HEADER_SIZE);
  grub_netbuff_put (nb, sizeof (struct dns_header)
		    + grub_strlen (name) + 2 + 4 + 2 + 4);
  head = (struct dns_header *) nb->data;
  optr = (grub_uint8_t *) (head + 1);
  for (iptr = name; *iptr; )
    {
      const char *dot;
      dot = grub_strchr (iptr, '.');
      if (!dot)
	dot = iptr + grub_strlen (iptr);
      if ((dot - iptr) >= 64)
	{
	  grub_free (data.name);
	  return grub_error (GRUB_ERR_BAD_ARGUMENT,
			     N_("domain name component is too long"));
	}
      *optr = (dot - iptr);
      optr++;
      grub_memcpy (optr, iptr, dot - iptr);
      optr += dot - iptr;
      iptr = dot;
      if (*iptr)
	iptr++;
    }
  *optr++ = 0;

  /* Type: A.  */
  *optr++ = 0;
  *optr++ = 1;

  /* Class.  */
  *optr++ = 0;
  *optr++ = 1;

  /* Compressed name.  */
  *optr++ = 0xc0;
  *optr++ = 0x0c;
  /* Type: AAAA.  */
  *optr++ = 0;
  *optr++ = 28;

  /* Class.  */
  *optr++ = 0;
  *optr++ = 1;

  head->id = data.id;
  head->flags = FLAGS_RD;
  head->ra_z_r_code = 0;
  head->qdcount = grub_cpu_to_be16_compile_time (2);
  head->ancount = grub_cpu_to_be16_compile_time (0);
  head->nscount = grub_cpu_to_be16_compile_time (0);
  head->arcount = grub_cpu_to_be16_compile_time (0);

  nbd = nb->data;

  for (i = 0; i < n_servers * 4; i++)
    {
      /* Connect to a next server.  */
      while (!(i & 1) && send_servers < n_servers)
	{
	  sockets[send_servers] = grub_net_udp_open (servers[send_servers],
						     DNS_PORT,
						     recv_hook,
						     &data);
	  send_servers++;
	  if (!sockets[send_servers - 1])
	    {
	      err = grub_errno;
	      grub_errno = GRUB_ERR_NONE;
	    }
	  else
	    {
	      have_server = 1;
	      break;
	    }
	}
      if (!have_server)
	goto out;
      if (*data.naddresses)
	goto out;
      for (j = 0; j < send_servers; j++)
	{
	  grub_err_t err2;
	  if (!sockets[j])
	    continue;
	  nb->data = nbd;
	  err2 = grub_net_send_udp_packet (sockets[j], nb);
	  if (err2)
	    {
	      grub_errno = GRUB_ERR_NONE;
	      err = err2;
	    }
	  if (*data.naddresses)
	    goto out;
	}
      grub_net_poll_cards (200);
    }
 out:
  grub_free (data.name);
  grub_netbuff_free (nb);
  for (j = 0; j < send_servers; j++)
    grub_net_udp_close (sockets[j]);
  
  if (*data.naddresses)
    return GRUB_ERR_NONE;
  if (data.dns_err)
    return grub_error (GRUB_ERR_NET_NO_DOMAIN,
		       N_("no DNS record found"));
    
  if (err)
    {
      grub_errno = err;
      return err;
    }
  return grub_error (GRUB_ERR_TIMEOUT,
		     N_("no DNS reply received"));
}
Пример #4
0
static grub_err_t 
recv_hook (grub_net_udp_socket_t sock __attribute__ ((unused)),
	   struct grub_net_buff *nb,
	   void *data_)
{
  struct dns_header *head;
  struct recv_data *data = data_;
  int i, j;
  grub_uint8_t *ptr, *reparse_ptr;
  int redirect_cnt = 0;
  char *redirect_save = NULL;
  grub_uint32_t ttl_all = ~0U;

  head = (struct dns_header *) nb->data;
  ptr = (grub_uint8_t *) (head + 1);
  if (ptr >= nb->tail)
    {
      grub_netbuff_free (nb);
      return GRUB_ERR_NONE;
    }
  
  if (head->id != data->id)
    {
      grub_netbuff_free (nb);
      return GRUB_ERR_NONE;
    }
  if (!(head->flags & FLAGS_RESPONSE) || (head->flags & FLAGS_OPCODE))
    {
      grub_netbuff_free (nb);
      return GRUB_ERR_NONE;
    }
  if (head->ra_z_r_code & ERRCODE_MASK)
    {
      data->dns_err = 1;
      grub_netbuff_free (nb);
      return GRUB_ERR_NONE;
    }
  for (i = 0; i < grub_cpu_to_be16 (head->qdcount); i++)
    {
      if (ptr >= nb->tail)
	{
	  grub_netbuff_free (nb);
	  return GRUB_ERR_NONE;
	}
      while (ptr < nb->tail && !((*ptr & 0xc0) || *ptr == 0))
	ptr += *ptr + 1;
      if (ptr < nb->tail && (*ptr & 0xc0))
	ptr++;
      ptr++;
      ptr += 4;
    }
  *data->addresses = grub_malloc (sizeof ((*data->addresses)[0])
				 * grub_cpu_to_be16 (head->ancount));
  if (!*data->addresses)
    {
      grub_errno = GRUB_ERR_NONE;
      grub_netbuff_free (nb);
      return GRUB_ERR_NONE;
    }
  reparse_ptr = ptr;
 reparse:
  for (i = 0, ptr = reparse_ptr; i < grub_cpu_to_be16 (head->ancount); i++)
    {
      int ignored = 0;
      grub_uint8_t class;
      grub_uint32_t ttl = 0;
      grub_uint16_t length;
      if (ptr >= nb->tail)
	{
	  if (!*data->naddresses)
	    grub_free (*data->addresses);
	  return GRUB_ERR_NONE;
	}
      ignored = !check_name (ptr, nb->data, nb->tail, data->name);
      while (ptr < nb->tail && !((*ptr & 0xc0) || *ptr == 0))
	ptr += *ptr + 1;
      if (ptr < nb->tail && (*ptr & 0xc0))
	ptr++;
      ptr++;
      if (ptr + 10 >= nb->tail)
	{
	  if (!*data->naddresses)
	    grub_free (*data->addresses);
	  grub_netbuff_free (nb);
	  return GRUB_ERR_NONE;
	}
      if (*ptr++ != 0)
	ignored = 1;
      class = *ptr++;
      if (*ptr++ != 0)
	ignored = 1;
      if (*ptr++ != 1)
	ignored = 1;
      for (j = 0; j < 4; j++)
	{
	  ttl <<= 8;
	  ttl |= *ptr++;
	}
      length = *ptr++ << 8;
      length |= *ptr++;
      if (ptr + length > nb->tail)
	{
	  if (!*data->naddresses)
	    grub_free (*data->addresses);
	  grub_netbuff_free (nb);
	  return GRUB_ERR_NONE;
	}
      if (!ignored)
	{
	  if (ttl_all > ttl)
	    ttl_all = ttl;
	  switch (class)
	    {
	    case DNS_CLASS_A:
	      if (length != 4)
		break;
	      (*data->addresses)[*data->naddresses].type
		= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
	      grub_memcpy (&(*data->addresses)[*data->naddresses].ipv4,
			   ptr, 4);
	      (*data->naddresses)++;
	      break;
	    case DNS_CLASS_AAAA:
	      if (length != 16)
		break;
	      (*data->addresses)[*data->naddresses].type
		= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
	      grub_memcpy (&(*data->addresses)[*data->naddresses].ipv6,
			   ptr, 16);
	      (*data->naddresses)++;
	      break;
	    case DNS_CLASS_CNAME:
	      if (!(redirect_cnt & (redirect_cnt - 1)))
		{
		  grub_free (redirect_save);
		  redirect_save = data->name;
		}
	      else
		grub_free (data->name);
	      redirect_cnt++;
	      data->name = get_name (ptr, nb->data, nb->tail);
	      if (!data->name)
		{
		  data->dns_err = 1;
		  grub_errno = 0;
		  return GRUB_ERR_NONE;
		}
	      grub_dprintf ("dns", "CNAME %s\n", data->name);
	      if (grub_strcmp (redirect_save, data->name) == 0)
		{
		  data->dns_err = 1;
		  grub_free (redirect_save);
		  return GRUB_ERR_NONE;
		}
	      goto reparse;
	    }
	}
      ptr += length;
    }
  if (ttl_all && *data->naddresses && data->cache)
    {
      int h;
      grub_dprintf ("dns", "caching for %d seconds\n", ttl_all);
      h = hash (data->oname);
      grub_free (dns_cache[h].name);
      dns_cache[h].name = 0;
      grub_free (dns_cache[h].addresses);
      dns_cache[h].addresses = 0;
      dns_cache[h].name = grub_strdup (data->oname);
      dns_cache[h].naddresses = *data->naddresses;
      dns_cache[h].addresses = grub_malloc (*data->naddresses
					    * sizeof (dns_cache[h].addresses[0]));
      dns_cache[h].limit_time = grub_get_time_ms () + 1000 * ttl_all;
      if (!dns_cache[h].addresses || !dns_cache[h].name)
	{
	  grub_free (dns_cache[h].name);
	  dns_cache[h].name = 0;
	  grub_free (dns_cache[h].addresses);
	  dns_cache[h].addresses = 0;
	}
      grub_memcpy (dns_cache[h].addresses, *data->addresses,
		   *data->naddresses
		   * sizeof (dns_cache[h].addresses[0]));
    }
  grub_netbuff_free (nb);
  grub_free (redirect_save);
  return GRUB_ERR_NONE;
}
Пример #5
0
int 
vstafs_dir (char *dirname)
{
  char *fn, ch;
  struct dir_entry *d;
  /* int l, i, s; */
  
  /*
   * Read in the entries of the current directory.
   */
  f_sector = ROOT_SECTOR;
  do
    {
      if (! (d = vstafs_readdir (f_sector)))
	{
	  return 0;
	}
      
      /*
       * Find the file in the path
       */
      while (*dirname == '/') dirname++;
      //fn = dirname;
      //while ((ch = *fn) && ch != '/' && ! isspace (ch)) fn++;
      for (fn = dirname; (ch = *fn) && ch != '/' && !isspace (ch); fn++)
      {
	if (ch == '\\')
	{
		fn++;
		if (! (ch = *fn))
			break;
	}
      }
      *fn = 0;
      
      do
	{
	  int j, k;
	  char ch1;
#ifdef GRUB_UTIL
	  char tmp_name[512];
#else
	  char *tmp_name = NAME_BUF;	/* MAXNAMLEN is 255, so 512 byte buffer is needed. */
#endif

	  if (d->name[0] == 0/* || d->name[0] & 0x80*/)
	    continue;
	  
	  /* copy d->name to tmp_name, and quote the spaces with a '\\' */
	  for (j = 0, k = 0; j < 28/*d->namlen*/; j++)
	  {
		if (! (ch1 = d->name[j]))
			break;
		if (ch1 == ' ')
			tmp_name[k++] = '\\';
		tmp_name[k++] = ch1;
	  }
	  tmp_name[k] = 0;

#ifndef STAGE1_5
	  if (print_possibilities && ch != '/'
	      && (! *dirname || strcmp (dirname, tmp_name) <= 0))
	    {
	      if (print_possibilities > 0)
		print_possibilities = -print_possibilities;
	      
	      //printf ("  %s", d->name);
	      print_a_completion (tmp_name);
	    }
#endif
	  if (! grub_strcmp (dirname, tmp_name))
	    {
	      f_sector = d->start;
	      get_file_info (f_sector);
	      filemax = FILE_INFO->len; 
	      break;
	    }
	}
      while ((d =vstafs_nextdir ()));
      
      *(dirname = fn) = ch;
      
      if (! d)
	{
	  if (print_possibilities < 0)
	    {
	      putchar ('\n');
	      return 1;
	    }
	  
	  errnum = ERR_FILE_NOT_FOUND;
	  return 0;
	}
    }
  while (*dirname && ! isspace (ch));
  
  return 1;
}
Пример #6
0
/* Eliminate "." and ".." path elements from PATH.  A new heap-allocated
   string is returned.  */
static char *
canonicalize_path (const char *path)
{
  int i;
  const char *p;
  char *newpath = 0;

  /* Count the path components in path.  */
  int components = 1;
  for (p = path; *p; p++)
    if (*p == '/')
      components++;

  char **path_array = grub_malloc (components * sizeof (*path_array));
  if (! path_array)
    return 0;

  /* Initialize array elements to NULL pointers; in case once of the
     allocations fails, the cleanup code can just call grub_free() for all
     pointers in the array.  */
  for (i = 0; i < components; i++)
    path_array[i] = 0;

  /* Parse the path into path_array.  */
  p = path;
  for (i = 0; i < components && p; i++)
    {
      /* Find the end of the path element.  */
      const char *end = grub_strchr (p, '/');
      if (!end)
        end = p + grub_strlen (p);

      /* Copy the element.  */
      path_array[i] = grub_new_substring (p, 0, end - p);
      if (! path_array[i])
        goto cleanup;

      /* Advance p to point to the start of the next element, or NULL.  */
      if (*end)
        p = end + 1;
      else
        p = 0;
    }

  /* Eliminate '.' and '..' elements from the path array.  */
  int newpath_length = 0;
  for (i = components - 1; i >= 0; --i)
    {
      if (! grub_strcmp (path_array[i], "."))
        {
          grub_free (path_array[i]);
          path_array[i] = 0;
        }
      else if (! grub_strcmp (path_array[i], "..")
               && i > 0)
        {
          /* Delete the '..' and the prior path element.  */
          grub_free (path_array[i]);
          path_array[i] = 0;
          --i;
          grub_free (path_array[i]);
          path_array[i] = 0;
        }
      else
        {
          newpath_length += grub_strlen (path_array[i]) + 1;
        }
    }

  /* Construct a new path string.  */
  newpath = grub_malloc (newpath_length + 1);
  if (! newpath)
    goto cleanup;

  newpath[0] = '\0';
  char *newpath_end = newpath;
  int first = 1;
  for (i = 0; i < components; i++)
    {
      char *element = path_array[i];
      if (element)
        {
          /* For all components but the first, prefix with a slash.  */
          if (! first)
            newpath_end = grub_stpcpy (newpath_end, "/");
          newpath_end = grub_stpcpy (newpath_end, element);
          first = 0;
        }
    }

cleanup:
  for (i = 0; i < components; i++)
    grub_free (path_array[i]);
  grub_free (path_array);

  return newpath;
}