X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fwps%2Fwps_upnp.c;h=4c0a5c1c834715bd3e75e97002e98cf62842f52c;hb=8c3a2f11ab13c9629c05a396c1f888d6a8685bfb;hp=148317cc8af5209cbc53828e03f67836735a3ffc;hpb=f98b440c47c06481768aa2607a3ad52ad95d769e;p=libeap.git diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c index 148317c..4c0a5c1 100644 --- a/src/wps/wps_upnp.c +++ b/src/wps/wps_upnp.c @@ -3,7 +3,7 @@ * Copyright (c) 2000-2003 Intel Corporation * Copyright (c) 2006-2007 Sony Corporation * Copyright (c) 2008-2009 Atheros Communications - * Copyright (c) 2009, Jouni Malinen + * Copyright (c) 2009-2010, Jouni Malinen * * See below for more details on licensing and code history. */ @@ -270,7 +270,7 @@ static void uuid_make(u8 uuid[UUID_LEN]) /* subscr_addr_delete -- delete single unlinked subscriber address * (be sure to unlink first if need be) */ -static void subscr_addr_delete(struct subscr_addr *a) +void subscr_addr_delete(struct subscr_addr *a) { /* * Note: do NOT free domain_and_port or path because they point to @@ -293,7 +293,8 @@ static void subscr_addr_free_all(struct subscription *s) /* subscr_addr_add_url -- add address(es) for one url to subscription */ -static void subscr_addr_add_url(struct subscription *s, const char *url) +static void subscr_addr_add_url(struct subscription *s, const char *url, + size_t url_len) { int alloc_len; char *scratch_mem = NULL; @@ -307,20 +308,21 @@ static void subscr_addr_add_url(struct subscription *s, const char *url) struct addrinfo *result = NULL; struct addrinfo *rp; int rerr; - struct subscr_addr *a = NULL; /* url MUST begin with http: */ - if (os_strncasecmp(url, "http://", 7)) + if (url_len < 7 || os_strncasecmp(url, "http://", 7)) goto fail; url += 7; + url_len -= 7; /* allocate memory for the extra stuff we need */ - alloc_len = (2 * (os_strlen(url) + 1)); + alloc_len = 2 * (url_len + 1); scratch_mem = os_zalloc(alloc_len); if (scratch_mem == NULL) goto fail; mem = scratch_mem; - strcpy(mem, url); + os_strncpy(mem, url, url_len); + wpa_printf(MSG_DEBUG, "WPS UPnP: Adding URL '%s'", mem); domain_and_port = mem; mem += 1 + os_strlen(mem); delim = os_strchr(domain_and_port, '/'); @@ -332,7 +334,7 @@ static void subscr_addr_add_url(struct subscription *s, const char *url) } domain = mem; strcpy(domain, domain_and_port); - delim = strchr(domain, ':'); + delim = os_strchr(domain, ':'); if (delim) { *delim++ = 0; /* null terminate domain */ if (isdigit(*delim)) @@ -367,6 +369,8 @@ static void subscr_addr_add_url(struct subscription *s, const char *url) goto fail; } for (rp = result; rp; rp = rp->ai_next) { + struct subscr_addr *a; + /* Limit no. of address to avoid denial of service attack */ if (dl_list_len(&s->addr_list) >= MAX_ADDR_PER_SUBSCRIPTION) { wpa_printf(MSG_INFO, "WPS UPnP: subscr_addr_add_url: " @@ -377,7 +381,6 @@ static void subscr_addr_add_url(struct subscription *s, const char *url) a = os_zalloc(sizeof(*a) + alloc_len); if (a == NULL) continue; - a->s = s; mem = (void *) (a + 1); a->domain_and_port = mem; strcpy(mem, domain_and_port); @@ -386,19 +389,17 @@ static void subscr_addr_add_url(struct subscription *s, const char *url) if (path[0] != '/') *mem++ = '/'; strcpy(mem, path); - mem += 1 + strlen(mem); + mem += 1 + os_strlen(mem); os_memcpy(&a->saddr, rp->ai_addr, sizeof(a->saddr)); a->saddr.sin_port = htons(port); dl_list_add(&s->addr_list, &a->list); - a = NULL; /* don't free it below */ } fail: if (result) freeaddrinfo(result); os_free(scratch_mem); - os_free(a); } @@ -408,7 +409,8 @@ fail: static void subscr_addr_list_create(struct subscription *s, const char *url_list) { - char *end; + const char *end; + wpa_printf(MSG_DEBUG, "WPS UPnP: Parsing URL list '%s'", url_list); for (;;) { while (*url_list == ' ' || *url_list == '\t') url_list++; @@ -418,9 +420,8 @@ static void subscr_addr_list_create(struct subscription *s, end = os_strchr(url_list, '>'); if (end == NULL) break; - *end++ = 0; - subscr_addr_add_url(s, url_list); - url_list = end; + subscr_addr_add_url(s, url_list, end - url_list); + url_list = end + 1; } } @@ -467,14 +468,14 @@ static void upnp_wps_device_send_event(struct upnp_wps_device_sm *sm) /* Enqueue event message for all subscribers */ struct wpabuf *buf; /* holds event message */ int buf_size = 0; - struct subscription *s; + struct subscription *s, *tmp; /* Actually, utf-8 is the default, but it doesn't hurt to specify it */ const char *format_head = "\n" "\n"; const char *format_tail = "\n"; - if (sm->subscriptions == NULL) { + if (dl_list_empty(&sm->subscriptions)) { /* optimize */ return; } @@ -496,19 +497,15 @@ static void upnp_wps_device_send_event(struct upnp_wps_device_sm *sm) wpa_printf(MSG_MSGDUMP, "WPS UPnP: WLANEvent message:\n%s", (char *) wpabuf_head(buf)); - s = sm->subscriptions; - do { - if (event_add(s, buf)) { - struct subscription *s_old = s; + dl_list_for_each_safe(s, tmp, &sm->subscriptions, struct subscription, + list) { + if (event_add(s, buf) == 1) { wpa_printf(MSG_INFO, "WPS UPnP: Dropping " - "subscriber due to event backlog"); - s = s_old->next; - subscription_unlink(s_old); - subscription_destroy(s_old); - } else { - s = s->next; + "subscriber %p due to event backlog", s); + dl_list_del(&s->list); + subscription_destroy(s); } - } while (s != sm->subscriptions); + } wpabuf_free(buf); } @@ -520,43 +517,6 @@ static void upnp_wps_device_send_event(struct upnp_wps_device_sm *sm) * This is the result of an incoming HTTP over TCP SUBSCRIBE request. */ -/* subscription_unlink -- remove from the active list */ -void subscription_unlink(struct subscription *s) -{ - struct upnp_wps_device_sm *sm = s->sm; - - if (s->next == s) { - /* only one? */ - sm->subscriptions = NULL; - } else { - if (sm->subscriptions == s) - sm->subscriptions = s->next; - s->next->prev = s->prev; - s->prev->next = s->next; - } - sm->n_subscriptions--; -} - - -/* subscription_link_to_end -- link to end of active list - * (should have high expiry time!) - */ -static void subscription_link_to_end(struct subscription *s) -{ - struct upnp_wps_device_sm *sm = s->sm; - - if (sm->subscriptions) { - s->next = sm->subscriptions; - s->prev = s->next->prev; - s->prev->next = s; - s->next->prev = s; - } else { - sm->subscriptions = s->next = s->prev = s; - } - sm->n_subscriptions++; -} - - /* subscription_destroy -- destroy an unlinked subscription * Be sure to unlink first if necessary. */ @@ -573,10 +533,13 @@ void subscription_destroy(struct subscription *s) /* subscription_list_age -- remove expired subscriptions */ static void subscription_list_age(struct upnp_wps_device_sm *sm, time_t now) { - struct subscription *s; - while ((s = sm->subscriptions) != NULL && s->timeout_time < now) { + struct subscription *s, *tmp; + dl_list_for_each_safe(s, tmp, &sm->subscriptions, + struct subscription, list) { + if (s->timeout_time > now) + break; wpa_printf(MSG_DEBUG, "WPS UPnP: Removing aged subscription"); - subscription_unlink(s); + dl_list_del(&s->list); subscription_destroy(s); } } @@ -588,17 +551,11 @@ static void subscription_list_age(struct upnp_wps_device_sm *sm, time_t now) struct subscription * subscription_find(struct upnp_wps_device_sm *sm, const u8 uuid[UUID_LEN]) { - struct subscription *s0 = sm->subscriptions; - struct subscription *s = s0; - - if (s0 == NULL) - return NULL; - do { + struct subscription *s; + dl_list_for_each(s, &sm->subscriptions, struct subscription, list) { if (os_memcmp(s->uuid, uuid, UUID_LEN) == 0) return s; /* Found match */ - s = s->next; - } while (s != s0); - + } return NULL; } @@ -610,8 +567,11 @@ static struct wpabuf * build_fake_wsc_ack(void) return NULL; wpabuf_put_u8(msg, UPNP_WPS_WLANEVENT_TYPE_EAP); wpabuf_put_str(msg, "00:00:00:00:00:00"); - wps_build_version(msg); - wps_build_msg_type(msg, WPS_WSC_ACK); + if (wps_build_version(msg) || + wps_build_msg_type(msg, WPS_WSC_ACK)) { + wpabuf_free(msg); + return NULL; + } /* Enrollee Nonce */ wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE); wpabuf_put_be16(msg, WPS_NONCE_LEN); @@ -620,6 +580,7 @@ static struct wpabuf * build_fake_wsc_ack(void) wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE); wpabuf_put_be16(msg, WPS_NONCE_LEN); wpabuf_put(msg, WPS_NONCE_LEN); + wps_build_wfa_ext(msg, 0, NULL, 0); return msg; } @@ -647,6 +608,7 @@ static int subscription_first_event(struct subscription *s) "\n"; const char *tail = "\n"; char txt[10]; + int ret; if (s->sm->wlanevent == NULL) { /* @@ -678,7 +640,7 @@ static int subscription_first_event(struct subscription *s) } buf = wpabuf_alloc(500 + os_strlen(wlan_event)); if (buf == NULL) - return 1; + return -1; wpabuf_put_str(buf, head); wpabuf_put_property(buf, "STAStatus", "1"); @@ -688,9 +650,10 @@ static int subscription_first_event(struct subscription *s) wpabuf_put_property(buf, "WLANEvent", wlan_event); wpabuf_put_str(buf, tail); - if (event_add(s, buf)) { + ret = event_add(s, buf); + if (ret) { wpabuf_free(buf); - return 1; + return ret; } wpabuf_free(buf); @@ -715,11 +678,12 @@ struct subscription * subscription_start(struct upnp_wps_device_sm *sm, subscription_list_age(sm, now); /* If too many subscriptions, remove oldest */ - if (sm->n_subscriptions >= MAX_SUBSCRIPTIONS) { - s = sm->subscriptions; + if (dl_list_len(&sm->subscriptions) >= MAX_SUBSCRIPTIONS) { + s = dl_list_first(&sm->subscriptions, struct subscription, + list); wpa_printf(MSG_INFO, "WPS UPnP: Too many subscriptions, " "trashing oldest"); - subscription_unlink(s); + dl_list_del(&s->list); subscription_destroy(s); } @@ -727,20 +691,28 @@ struct subscription * subscription_start(struct upnp_wps_device_sm *sm, if (s == NULL) return NULL; dl_list_init(&s->addr_list); + dl_list_init(&s->event_queue); s->sm = sm; s->timeout_time = expire; uuid_make(s->uuid); subscr_addr_list_create(s, callback_urls); + if (dl_list_empty(&s->addr_list)) { + wpa_printf(MSG_DEBUG, "WPS UPnP: No valid callback URLs in " + "'%s' - drop subscription", callback_urls); + subscription_destroy(s); + return NULL; + } + /* Add to end of list, since it has the highest expiration time */ - subscription_link_to_end(s); + dl_list_add_tail(&sm->subscriptions, &s->list); /* Queue up immediate event message (our last event) * as required by UPnP spec. */ if (subscription_first_event(s)) { wpa_printf(MSG_INFO, "WPS UPnP: Dropping subscriber due to " "event backlog"); - subscription_unlink(s); + dl_list_del(&s->list); subscription_destroy(s); return NULL; } @@ -762,10 +734,10 @@ struct subscription * subscription_renew(struct upnp_wps_device_sm *sm, if (s == NULL) return NULL; wpa_printf(MSG_DEBUG, "WPS UPnP: Subscription renewed"); - subscription_unlink(s); + dl_list_del(&s->list); s->timeout_time = expire; /* add back to end of list, since it now has highest expiry */ - subscription_link_to_end(s); + dl_list_add_tail(&sm->subscriptions, &s->list); return s; } @@ -837,7 +809,7 @@ fail: } -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include #include #include @@ -887,11 +859,10 @@ static int eth_get(const char *device, u8 ea[ETH_ALEN]) * @ip_addr: Buffer for returning IP address in network byte order * @ip_addr_text: Buffer for returning a pointer to allocated IP address text * @mac: Buffer for returning MAC address - * @mac_addr_text: Buffer for returning allocated MAC address text * Returns: 0 on success, -1 on failure */ int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text, - u8 mac[ETH_ALEN], char **mac_addr_text) + u8 mac[ETH_ALEN]) { struct ifreq req; int sock = -1; @@ -899,8 +870,7 @@ int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text, struct in_addr in_addr; *ip_addr_text = os_zalloc(16); - *mac_addr_text = os_zalloc(18); - if (*ip_addr_text == NULL || *mac_addr_text == NULL) + if (*ip_addr_text == NULL) goto fail; sock = socket(AF_INET, SOCK_DGRAM, 0); @@ -926,7 +896,7 @@ int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text, goto fail; } os_memcpy(mac, req.ifr_addr.sa_data, 6); -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) if (eth_get(net_if, mac) < 0) { wpa_printf(MSG_ERROR, "WPS UPnP: Failed to get MAC address"); goto fail; @@ -934,7 +904,6 @@ int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text, #else #error MAC address fetch not implemented #endif - os_snprintf(*mac_addr_text, 18, MACSTR, MAC2STR(mac)); close(sock); return 0; @@ -944,12 +913,29 @@ fail: close(sock); os_free(*ip_addr_text); *ip_addr_text = NULL; - os_free(*mac_addr_text); - *mac_addr_text = NULL; return -1; } +static void upnp_wps_free_msearchreply(struct dl_list *head) +{ + struct advertisement_state_machine *a, *tmp; + dl_list_for_each_safe(a, tmp, head, struct advertisement_state_machine, + list) + msearchreply_state_machine_stop(a); +} + + +static void upnp_wps_free_subscriptions(struct dl_list *head) +{ + struct subscription *s, *tmp; + dl_list_for_each_safe(s, tmp, head, struct subscription, list) { + dl_list_del(&s->list); + subscription_destroy(s); + } +} + + /** * upnp_wps_device_stop - Stop WPS UPnP operations on an interface * @sm: WPS UPnP state machine from upnp_wps_device_init() @@ -961,23 +947,14 @@ void upnp_wps_device_stop(struct upnp_wps_device_sm *sm) wpa_printf(MSG_DEBUG, "WPS UPnP: Stop device"); web_listener_stop(sm); - while (sm->msearch_replies) - msearchreply_state_machine_stop(sm->msearch_replies); - while (sm->subscriptions) { - struct subscription *s = sm->subscriptions; - subscription_unlink(s); - subscription_destroy(s); - } + upnp_wps_free_msearchreply(&sm->msearch_replies); + upnp_wps_free_subscriptions(&sm->subscriptions); advertisement_state_machine_stop(sm, 1); event_send_stop_all(sm); os_free(sm->wlanevent); sm->wlanevent = NULL; - os_free(sm->net_if); - sm->net_if = NULL; - os_free(sm->mac_addr_text); - sm->mac_addr_text = NULL; os_free(sm->ip_addr_text); sm->ip_addr_text = NULL; if (sm->multicast_sd >= 0) @@ -1003,7 +980,6 @@ int upnp_wps_device_start(struct upnp_wps_device_sm *sm, char *net_if) if (sm->started) upnp_wps_device_stop(sm); - sm->net_if = strdup(net_if); sm->multicast_sd = -1; sm->ssdp_sd = -1; sm->started = 1; @@ -1014,9 +990,8 @@ int upnp_wps_device_start(struct upnp_wps_device_sm *sm, char *net_if) goto fail; /* Determine which IP and mac address we're using */ - if (get_netif_info(net_if, - &sm->ip_addr, &sm->ip_addr_text, - sm->mac_addr, &sm->mac_addr_text)) { + if (get_netif_info(net_if, &sm->ip_addr, &sm->ip_addr_text, + sm->mac_addr)) { wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address " "for %s. Does it have IP address?", net_if); goto fail; @@ -1095,6 +1070,8 @@ upnp_wps_device_init(struct upnp_wps_device_ctx *ctx, struct wps_context *wps, sm->ctx = ctx; sm->wps = wps; sm->priv = priv; + dl_list_init(&sm->msearch_replies); + dl_list_init(&sm->subscriptions); return sm; } @@ -1107,5 +1084,22 @@ upnp_wps_device_init(struct upnp_wps_device_ctx *ctx, struct wps_context *wps, */ int upnp_wps_subscribers(struct upnp_wps_device_sm *sm) { - return sm->subscriptions != NULL; + return !dl_list_empty(&sm->subscriptions); +} + + +int upnp_wps_set_ap_pin(struct upnp_wps_device_sm *sm, const char *ap_pin) +{ + if (sm == NULL) + return 0; + + os_free(sm->ctx->ap_pin); + if (ap_pin) { + sm->ctx->ap_pin = os_strdup(ap_pin); + if (sm->ctx->ap_pin == NULL) + return -1; + } else + sm->ctx->ap_pin = NULL; + + return 0; }