static int ni_dhcp_option_next(ni_buffer_t *bp, ni_buffer_t *optbuf) { unsigned char code, count; if (bp->underflow) return -1; if (bp->head == bp->tail) return DHCP_END; if (bp->tail - bp->head < 2) goto underflow; code = bp->base[bp->head++]; if (code != DHCP_PAD && code != DHCP_END) { count = bp->base[bp->head++]; if (bp->tail - bp->head < count) goto underflow; ni_buffer_init_reader(optbuf, bp->base + bp->head, count); bp->head += count; } else { memset(optbuf, 0, sizeof(*optbuf)); } return code; underflow: bp->underflow = 1; return -1; }
/* * Tmpfile.upload(path, offset, data) */ static dbus_bool_t __ni_Testbus_Agent_Filesystem_upload(ni_dbus_object_t *object, const ni_dbus_method_t *method, unsigned int argc, const ni_dbus_variant_t *argv, ni_dbus_message_t *reply, DBusError *error) { ni_buffer_t wbuf; const char *path; uint64_t offset; unsigned int written = 0; int fd; if (argc != 3 || !ni_dbus_variant_get_string(&argv[0], &path) || path[0] != '/' || !ni_dbus_variant_get_uint64(&argv[1], &offset) || !ni_dbus_variant_is_byte_array(&argv[2])) return ni_dbus_error_invalid_args(error, object->path, method->name); if (offset == 0) fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644); else fd = open(path, O_WRONLY); if (fd < 0) { ni_dbus_set_error_from_errno(error, errno, "unable to open file \"%s\"", path); return FALSE; } if (lseek(fd, offset, SEEK_SET) < 0) { ni_dbus_set_error_from_errno(error, errno, "seek faile"); goto out_fail; } ni_buffer_init_reader(&wbuf, argv[2].byte_array_value, argv[2].array.len); while (ni_buffer_count(&wbuf)) { int n; n = write(fd, ni_buffer_head(&wbuf), ni_buffer_count(&wbuf)); if (n < 0) { ni_dbus_set_error_from_errno(error, errno, "error writing to \"%s\" at offset %Lu", path, (unsigned long long) offset + written); goto out_fail; } ni_buffer_pull_head(&wbuf, n); written += n; } close(fd); ni_debug_testbus("%s: wrote %u bytes at offset %Lu", path, written, (unsigned long long) offset); return TRUE; out_fail: if (fd >= 0) close(fd); return FALSE; }
static inline int __ni_wireless_process_wpa2(ni_wireless_network_t *net, void *ptr, size_t len) { static unsigned char wpa2_oui[] = {0x00, 0x0f, 0xac}; ni_buffer_t data; ni_buffer_init_reader(&data, ptr, len); return __ni_wireless_process_wpa_common(net, &data, NI_WIRELESS_AUTH_WPA2, wpa2_oui); }
xml_document_t * xml_document_from_string(const char *string, const char *location) { ni_buffer_t buf; if (string == NULL) { ni_error("%s: argument string is NULL", __func__); return NULL; } ni_buffer_init_reader(&buf, (char *) string, strlen(string)); return xml_document_from_buffer(&buf, location); }
int __ni_wireless_process_ie(ni_wireless_network_t *net, void *ptr, size_t len) { ni_buffer_t data; ni_buffer_init_reader(&data, ptr, len); while (ni_buffer_count(&data) >= 2) { unsigned char type, len; int rv = -1; if (ni_buffer_get(&data, &type, 1) < 0 || ni_buffer_get(&data, &len, 1) < 0) goto format_error; if (ni_buffer_count(&data) < len) goto format_error; ptr = ni_buffer_head(&data); data.head += len; switch (type) { case 0xdd: rv = __ni_wireless_process_wpa1(net, ptr, len); break; case 0x30: rv = __ni_wireless_process_wpa2(net, ptr, len); break; default: ni_debug_wireless("Skipping unsupported Informaton Element 0x%02x", type); continue; } if (rv < 0) return -1; } return 0; format_error: ni_error("error processing wireless Information Elements"); return -1; }
static inline int __ni_wireless_process_wpa1(ni_wireless_network_t *net, void *ptr, size_t len) { static unsigned char wpa1_oui[] = {0x00, 0x50, 0xf2}; unsigned char buffer[3]; ni_buffer_t data; ni_buffer_init_reader(&data, ptr, len); if (ni_buffer_get(&data, buffer, 3) < 0) return -1; if (memcmp(buffer, wpa1_oui, 3)) { ni_debug_ifconfig("skipping non-WPA1 IE (OUI=%02x:%02x:%02x)", buffer[0], buffer[1], buffer[0]); return 0; } if (ni_buffer_get(&data, buffer, 1) < 0) return -1; if (buffer[0] != 0x01) return 0; return __ni_wireless_process_wpa_common(net, &data, NI_WIRELESS_AUTH_WPA1, wpa1_oui); }
/* * Parse a DHCP response. * FIXME: RFC2131 states that the server is allowed to split a DHCP option into * several (partial) options if the total length exceeds 255 octets. We don't * handle this yet. */ int ni_dhcp_parse_response(const ni_dhcp_message_t *message, ni_buffer_t *options, ni_addrconf_lease_t **leasep) { ni_buffer_t overload_buf; ni_addrconf_lease_t *lease; ni_route_array_t default_routes = NI_ROUTE_ARRAY_INIT; ni_route_array_t static_routes = NI_ROUTE_ARRAY_INIT; ni_route_array_t classless_routes = NI_ROUTE_ARRAY_INIT; ni_string_array_t dns_servers = NI_STRING_ARRAY_INIT; ni_string_array_t dns_search = NI_STRING_ARRAY_INIT; ni_string_array_t nis_servers = NI_STRING_ARRAY_INIT; char *nisdomain = NULL; char *dnsdomain = NULL; int opt_overload = 0; int msg_type = -1; int use_bootserver = 1; int use_bootfile = 1; lease = ni_addrconf_lease_new(NI_ADDRCONF_DHCP, AF_INET); lease->state = NI_ADDRCONF_STATE_GRANTED; lease->type = NI_ADDRCONF_DHCP; lease->family = AF_INET; lease->time_acquired = time(NULL); lease->dhcp.address.s_addr = message->yiaddr; lease->dhcp.serveraddress.s_addr = message->siaddr; lease->dhcp.address.s_addr = message->yiaddr; parse_more: /* Loop as long as we still have data in the buffer. */ while (ni_buffer_count(options) && !options->underflow) { ni_buffer_t buf; int option; option = ni_dhcp_option_next(options, &buf); //ni_debug_dhcp("handle option %s (%d)", ni_dhcp_option_name(option), option); if (option == DHCP_PAD) continue; if (option == DHCP_END) break; if (option < 0) goto error; if (ni_buffer_count(&buf) == 0) { ni_error("option %d has zero length", option); goto error; } switch (option) { case DHCP_MESSAGETYPE: msg_type = ni_buffer_getc(&buf); if (msg_type < 0) goto error; continue; case DHCP_ADDRESS: ni_dhcp_option_get_ipv4(&buf, &lease->dhcp.address); break; case DHCP_NETMASK: ni_dhcp_option_get_ipv4(&buf, &lease->dhcp.netmask); break; case DHCP_BROADCAST: ni_dhcp_option_get_ipv4(&buf, &lease->dhcp.broadcast); break; case DHCP_SERVERIDENTIFIER: ni_dhcp_option_get_ipv4(&buf, &lease->dhcp.serveraddress); break; case DHCP_LEASETIME: ni_dhcp_option_get32(&buf, &lease->dhcp.lease_time); break; case DHCP_RENEWALTIME: ni_dhcp_option_get32(&buf, &lease->dhcp.renewal_time); break; case DHCP_REBINDTIME: ni_dhcp_option_get32(&buf, &lease->dhcp.rebind_time); break; case DHCP_MTU: ni_dhcp_option_get16(&buf, &lease->dhcp.mtu); /* Minimum legal mtu is 68 accoridng to * RFC 2132. In practise it's 576 which is the * minimum maximum message size. */ if (lease->dhcp.mtu < MTU_MIN) { ni_debug_dhcp("MTU %u is too low, minimum is %d; ignoring", lease->dhcp.mtu, MTU_MIN); lease->dhcp.mtu = 0; } break; case DHCP_HOSTNAME: ni_dhcp_option_get_domain(&buf, &lease->hostname, "hostname"); break; case DHCP_DNSDOMAIN: ni_dhcp_option_get_domain(&buf, &dnsdomain, "dns-domain"); break; case DHCP_MESSAGE: ni_dhcp_option_get_printable(&buf, &lease->dhcp.message, "dhcp-message"); break; case DHCP_ROOTPATH: ni_dhcp_option_get_pathname(&buf, &lease->dhcp.rootpath, "root-path"); break; case DHCP_NISDOMAIN: ni_dhcp_option_get_domain(&buf, &nisdomain, "nis-domain"); break; case DHCP_NETBIOSNODETYPE: ni_dhcp_option_get_netbios_type(&buf, &lease->netbios_type); break; case DHCP_NETBIOSSCOPE: ni_dhcp_option_get_domain(&buf, &lease->netbios_scope, "netbios-scope"); break; case DHCP_DNSSERVER: ni_dhcp_decode_address_list(&buf, &dns_servers); break; case DHCP_NTPSERVER: ni_dhcp_decode_address_list(&buf, &lease->ntp_servers); break; case DHCP_NISSERVER: ni_dhcp_decode_address_list(&buf, &nis_servers); break; case DHCP_LPRSERVER: ni_dhcp_decode_address_list(&buf, &lease->lpr_servers); break; case DHCP_LOGSERVER: ni_dhcp_decode_address_list(&buf, &lease->log_servers); break; case DHCP_NETBIOSNAMESERVER: ni_dhcp_decode_address_list(&buf, &lease->netbios_name_servers); break; case DHCP_NETBIOSDDSERVER: ni_dhcp_decode_address_list(&buf, &lease->netbios_dd_servers); break; case DHCP_DNSSEARCH: ni_dhcp_decode_dnssearch(&buf, &dns_search, "dns-search domain"); break; case DHCP_CSR: case DHCP_MSCSR: ni_route_array_destroy(&classless_routes); if (ni_dhcp_decode_csr(&buf, &classless_routes) < 0) goto error; break; case DHCP_SIPSERVER: ni_dhcp_decode_sipservers(&buf, &lease->sip_servers); break; case DHCP_STATICROUTE: ni_route_array_destroy(&static_routes); if (ni_dhcp_decode_static_routes(&buf, &static_routes) < 0) goto error; break; case DHCP_ROUTERS: ni_route_array_destroy(&default_routes); if (ni_dhcp_decode_routers(&buf, &default_routes) < 0) goto error; break; case DHCP_OPTIONSOVERLOADED: if (options != &overload_buf) { opt_overload = ni_buffer_getc(&buf); } else { ni_debug_dhcp("DHCP: ignoring OVERLOAD option in overloaded data"); (void) ni_buffer_getc(&buf); } break; case DHCP_FQDN: /* We ignore replies about FQDN */ break; default: ni_debug_dhcp("ignoring unsupported DHCP code %u", option); break; } if (buf.underflow) { ni_debug_dhcp("unable to parse DHCP option %s: too short", ni_dhcp_option_name(option)); goto error; } else if (ni_buffer_count(&buf)) { ni_debug_dhcp("excess data in DHCP option %s - %u bytes left", ni_dhcp_option_name(option), ni_buffer_count(&buf)); } } if (options->underflow) { ni_debug_dhcp("unable to parse DHCP response: truncated packet"); goto error; } if (opt_overload) { const void *more_data = NULL; size_t size = 0; if (opt_overload & DHCP_OVERLOAD_BOOTFILE) { use_bootfile = 0; more_data = message->bootfile; size = sizeof(message->bootfile); opt_overload &= ~DHCP_OVERLOAD_BOOTFILE; } else if (opt_overload & DHCP_OVERLOAD_SERVERNAME) { use_bootserver = 0; more_data = message->servername; size = sizeof(message->servername); opt_overload &= ~DHCP_OVERLOAD_SERVERNAME; } else { opt_overload = 0; } if (more_data) { ni_buffer_init_reader(&overload_buf, (void *) more_data, size); options = &overload_buf; goto parse_more; } } if (use_bootserver && message->servername[0]) { char tmp[sizeof(message->servername)]; size_t len; assert(sizeof(lease->dhcp.servername) == sizeof(message->servername)); memcpy(tmp, message->servername, sizeof(tmp)); tmp[sizeof(tmp)-1] = '\0'; len = ni_string_len(tmp); if (ni_check_domain_name(tmp, len, 0)) { memcpy(lease->dhcp.servername, tmp, sizeof(lease->dhcp.servername)); } else { ni_debug_dhcp("Discarded suspect boot-server name: %s", ni_print_suspect(tmp, len)); } } if (use_bootfile && message->bootfile[0]) { char tmp[sizeof(message->bootfile)]; size_t len; memcpy(tmp, message->bootfile, sizeof(tmp)); tmp[sizeof(tmp)-1] = '\0'; len = ni_string_len(tmp); if (ni_check_pathname(tmp, len)) { ni_string_dup(&lease->dhcp.bootfile, tmp); } else { ni_debug_dhcp("Discarded suspect boot-file name: %s", ni_print_suspect(tmp, len)); } } /* Fill in any missing fields */ if (!lease->dhcp.netmask.s_addr) { unsigned int pfxlen = guess_prefix_len(lease->dhcp.address); lease->dhcp.netmask.s_addr = htonl(~(0xFFFFFFFF >> pfxlen)); }
/* * Decode an RFC3397 DNS search order option. */ static int ni_dhcp_decode_dnssearch(ni_buffer_t *optbuf, ni_string_array_t *list, const char *what) { ni_stringbuf_t namebuf = NI_STRINGBUF_INIT_DYNAMIC; unsigned char *base = ni_buffer_head(optbuf); unsigned int base_offset = optbuf->head; size_t len; ni_string_array_destroy(list); while (ni_buffer_count(optbuf) && !optbuf->underflow) { ni_buffer_t *bp = optbuf; ni_buffer_t jumpbuf; while (1) { unsigned int pos = bp->head - base_offset; unsigned int pointer; char label[64]; int length; if ((length = ni_buffer_getc(bp)) < 0) goto failure; /* unexpected EOF */ if (length == 0) break; /* end of this name */ switch (length & 0xC0) { case 0: /* Plain name component */ if (ni_buffer_get(bp, label, length) < 0) goto failure; label[length] = '\0'; if (!ni_stringbuf_empty(&namebuf)) ni_stringbuf_putc(&namebuf, '.'); ni_stringbuf_puts(&namebuf, label); break; case 0xC0: /* Pointer */ pointer = (length & 0x3F) << 8; if ((length = ni_buffer_getc(bp)) < 0) goto failure; pointer |= length; if (pointer >= pos) goto failure; ni_buffer_init_reader(&jumpbuf, base, pos); jumpbuf.head = pointer; bp = &jumpbuf; break; default: goto failure; } } if (!ni_stringbuf_empty(&namebuf)) { len = ni_string_len(namebuf.string); if (ni_check_domain_name(namebuf.string, len, 0)) { ni_string_array_append(list, namebuf.string); } else { ni_debug_dhcp("Discarded suspect %s: %s", what, ni_print_suspect(namebuf.string, len)); } } ni_stringbuf_destroy(&namebuf); } return 0; failure: ni_stringbuf_destroy(&namebuf); ni_string_array_destroy(list); return -1; }