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; }
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; }
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")); }
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; }
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; }
/* 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; }