static struct wpabuf * event_build_message(struct wps_event_ *e) { struct wpabuf *buf; char *b; buf = wpabuf_alloc(1000 + wpabuf_len(e->data)); if (buf == NULL) return NULL; wpabuf_printf(buf, "NOTIFY %s HTTP/1.1\r\n", e->addr->path); wpabuf_put_str(buf, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n"); wpabuf_printf(buf, "HOST: %s\r\n", e->addr->domain_and_port); wpabuf_put_str(buf, "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n" "NT: upnp:event\r\n" "NTS: upnp:propchange\r\n"); wpabuf_put_str(buf, "SID: uuid:"); b = wpabuf_put(buf, 0); uuid_bin2str(e->s->uuid, b, 80); wpabuf_put(buf, os_strlen(b)); wpabuf_put_str(buf, "\r\n"); wpabuf_printf(buf, "SEQ: %u\r\n", e->subscriber_sequence); wpabuf_printf(buf, "CONTENT-LENGTH: %d\r\n", (int) wpabuf_len(e->data)); wpabuf_put_str(buf, "\r\n"); /* terminating empty line */ wpabuf_put_buf(buf, e->data); return buf; }
static void wpabuf_put_property(struct wpabuf *buf, const char *name, const char *value) { wpabuf_put_str(buf, "<e:property>"); wpabuf_printf(buf, "<%s>", name); if (value) wpabuf_put_str(buf, value); wpabuf_printf(buf, "</%s>", name); wpabuf_put_str(buf, "</e:property>\n"); }
static struct wpabuf * wps_er_soap_hdr(const struct wpabuf *msg, const char *name, const char *arg_name, const char *path, const struct sockaddr_in *dst, char **len_ptr, char **body_ptr) { unsigned char *encoded; size_t encoded_len; struct wpabuf *buf; if (msg) { encoded = base64_encode(wpabuf_head(msg), wpabuf_len(msg), &encoded_len); if (encoded == NULL) return NULL; } else { encoded = NULL; encoded_len = 0; } buf = wpabuf_alloc(1000 + encoded_len); if (buf == NULL) { os_free(encoded); return NULL; } wpabuf_printf(buf, "POST %s HTTP/1.1\r\n" "Host: %s:%d\r\n" "Content-Type: text/xml; charset=\"utf-8\"\r\n" "Content-Length: ", path, inet_ntoa(dst->sin_addr), ntohs(dst->sin_port)); *len_ptr = wpabuf_put(buf, 0); wpabuf_printf(buf, " \r\n" "SOAPACTION: \"%s#%s\"\r\n" "\r\n", urn_wfawlanconfig, name); *body_ptr = wpabuf_put(buf, 0); wpabuf_put_str(buf, soap_prefix); wpabuf_printf(buf, "<u:%s xmlns:u=\"", name); wpabuf_put_str(buf, urn_wfawlanconfig); wpabuf_put_str(buf, "\">\n"); if (encoded) { wpabuf_printf(buf, "<%s>%s</%s>\n", arg_name, (char *) encoded, arg_name); os_free(encoded); } return buf; }
static void wps_er_sta_send_msg(struct wps_er_sta *sta, struct wpabuf *msg) { struct wpabuf *buf; char *len_ptr, *body_ptr; struct sockaddr_in dst; char *url, *path; if (sta->http) { wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for STA - " "ignore new request"); wpabuf_free(msg); return; } if (sta->ap->control_url == NULL) { wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP"); wpabuf_free(msg); return; } url = http_client_url_parse(sta->ap->control_url, &dst, &path); if (url == NULL) { wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL"); wpabuf_free(msg); return; } buf = wps_er_soap_hdr(msg, "PutWLANResponse", "NewMessage", path, &dst, &len_ptr, &body_ptr); wpabuf_free(msg); os_free(url); if (buf == NULL) return; wpabuf_printf(buf, "<NewWLANEventType>%d</NewWLANEventType>\n", UPNP_WPS_WLANEVENT_TYPE_EAP); wpabuf_printf(buf, "<NewWLANEventMAC>" MACSTR "</NewWLANEventMAC>\n", MAC2STR(sta->addr)); wps_er_soap_end(buf, "PutWLANResponse", len_ptr, body_ptr); sta->http = http_client_addr(&dst, buf, 1000, wps_er_http_put_wlan_response_cb, sta); if (sta->http == NULL) wpabuf_free(buf); }
static void wps_er_soap_end(struct wpabuf *buf, const char *name, char *len_ptr, char *body_ptr) { char len_buf[10]; wpabuf_printf(buf, "</u:%s>\n", name); wpabuf_put_str(buf, soap_postfix); os_snprintf(len_buf, sizeof(len_buf), "%d", (int) ((char *) wpabuf_put(buf, 0) - body_ptr)); os_memcpy(len_ptr, len_buf, os_strlen(len_buf)); }
static void wps_er_ap_unsubscribe(struct wps_er *er, struct wps_er_ap *ap) { struct wpabuf *req; struct sockaddr_in dst; char *url, *path; char sid[100]; if (ap->event_sub_url == NULL) { wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot " "subscribe"); goto fail; } if (ap->http) { wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot " "send subscribe request"); goto fail; } url = http_client_url_parse(ap->event_sub_url, &dst, &path); if (url == NULL) { wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL"); goto fail; } req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000); if (req == NULL) { os_free(url); goto fail; } uuid_bin2str(ap->sid, sid, sizeof(sid)); wpabuf_printf(req, "UNSUBSCRIBE %s HTTP/1.1\r\n" "HOST: %s:%d\r\n" "SID: uuid:%s\r\n" "\r\n", path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port), sid); os_free(url); wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Unsubscription request", wpabuf_head(req), wpabuf_len(req)); ap->http = http_client_addr(&dst, req, 1000, wps_er_http_unsubscribe_cb, ap); if (ap->http == NULL) { wpabuf_free(req); goto fail; } return; fail: /* * Need to get rid of the AP entry even when we fail to unsubscribe * cleanly. */ wps_er_ap_unsubscribed(ap->er, ap); }
/* Write the current date/time per RFC */ void format_date(struct wpabuf *buf) { const char *weekday_str = "Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat"; const char *month_str = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0" "Jul\0Aug\0Sep\0Oct\0Nov\0Dec"; struct tm *date; time_t t; t = time(NULL); date = gmtime(&t); wpabuf_printf(buf, "%s, %02d %s %d %02d:%02d:%02d GMT", &weekday_str[date->tm_wday * 4], date->tm_mday, &month_str[date->tm_mon * 4], date->tm_year + 1900, date->tm_hour, date->tm_min, date->tm_sec); }
static void wps_er_subscribe(struct wps_er_ap *ap) { struct wpabuf *req; struct sockaddr_in dst; char *url, *path; if (ap->event_sub_url == NULL) { wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot " "subscribe"); return; } if (ap->http) { wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot " "send subscribe request"); return; } url = http_client_url_parse(ap->event_sub_url, &dst, &path); if (url == NULL) { wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL"); return; } req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000); if (req == NULL) { os_free(url); return; } wpabuf_printf(req, "SUBSCRIBE %s HTTP/1.1\r\n" "HOST: %s:%d\r\n" "CALLBACK: <http://%s:%d/event/%u/%u>\r\n" "NT: upnp:event\r\n" "TIMEOUT: Second-%d\r\n" "\r\n", path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port), ap->er->ip_addr_text, ap->er->http_port, ap->er->event_id, ap->id, 1800); os_free(url); wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Subscription request", wpabuf_head(req), wpabuf_len(req)); ap->http = http_client_addr(&dst, req, 1000, wps_er_http_subscribe_cb, ap); if (ap->http == NULL) wpabuf_free(req); }
struct http_client * http_client_url(const char *url, struct wpabuf *req, size_t max_response, void (*cb)(void *ctx, struct http_client *c, enum http_client_event event), void *cb_ctx) { struct sockaddr_in dst; struct http_client *c; char *u, *path; struct wpabuf *req_buf = NULL; if (os_strncmp(url, "http://", 7) != 0) return NULL; u = http_client_url_parse(url, &dst, &path); if (u == NULL) return NULL; if (req == NULL) { req_buf = wpabuf_alloc(os_strlen(url) + 1000); if (req_buf == NULL) { os_free(u); return NULL; } req = req_buf; wpabuf_printf(req, "GET %s HTTP/1.1\r\n" "Cache-Control: no-cache\r\n" "Pragma: no-cache\r\n" "Accept: text/xml, application/xml\r\n" "User-Agent: wpa_supplicant\r\n" "Host: %s:%d\r\n" "\r\n", path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port)); } os_free(u); c = http_client_addr(&dst, req, max_response, cb, cb_ctx); if (c == NULL) { wpabuf_free(req_buf); return NULL; } return c; }
static void web_connection_send_reply(struct http_request *req, enum http_reply_code ret, const char *action, int action_len, const struct wpabuf *reply, const char *replyname) { struct wpabuf *buf; char *replydata; char *put_length_here = NULL; char *body_start = NULL; if (reply) { size_t len; replydata = (char *) base64_encode(wpabuf_head(reply), wpabuf_len(reply), &len); } else replydata = NULL; /* Parameters of the response: * action(action_len) -- action we are responding to * replyname -- a name we need for the reply * replydata -- NULL or null-terminated string */ buf = wpabuf_alloc(1000 + (replydata ? os_strlen(replydata) : 0U) + (action_len > 0 ? action_len * 2 : 0)); if (buf == NULL) { wpa_printf(MSG_INFO, "WPS UPnP: Cannot allocate reply to " "POST"); os_free(replydata); http_request_deinit(req); return; } /* * Assuming we will be successful, put in the output header first. * Note: we do not keep connections alive (and httpread does * not support it)... therefore we must have Connection: close. */ if (ret == HTTP_OK) { wpabuf_put_str(buf, "HTTP/1.1 200 OK\r\n" "Content-Type: text/xml; " "charset=\"utf-8\"\r\n"); } else { wpabuf_printf(buf, "HTTP/1.1 %d Error\r\n", ret); } wpabuf_put_str(buf, http_connection_close); wpabuf_put_str(buf, "Content-Length: "); /* * We will paste the length in later, leaving some extra whitespace. * HTTP code is supposed to be tolerant of extra whitespace. */ put_length_here = wpabuf_put(buf, 0); wpabuf_put_str(buf, " \r\n"); http_put_date(buf); /* terminating empty line */ wpabuf_put_str(buf, "\r\n"); body_start = wpabuf_put(buf, 0); if (ret == HTTP_OK) { wpabuf_put_str(buf, soap_prefix); wpabuf_put_str(buf, "<u:"); wpabuf_put_data(buf, action, action_len); wpabuf_put_str(buf, "Response xmlns:u=\""); wpabuf_put_str(buf, urn_wfawlanconfig); wpabuf_put_str(buf, "\">\n"); if (replydata && replyname) { /* TODO: might possibly need to escape part of reply * data? ... * probably not, unlikely to have ampersand(&) or left * angle bracket (<) in it... */ wpabuf_printf(buf, "<%s>", replyname); wpabuf_put_str(buf, replydata); wpabuf_printf(buf, "</%s>\n", replyname); } wpabuf_put_str(buf, "</u:"); wpabuf_put_data(buf, action, action_len); wpabuf_put_str(buf, "Response>\n"); wpabuf_put_str(buf, soap_postfix); } else { /* Error case */ wpabuf_put_str(buf, soap_prefix); wpabuf_put_str(buf, soap_error_prefix); wpabuf_printf(buf, "<errorCode>%d</errorCode>\n", ret); wpabuf_put_str(buf, soap_error_postfix); wpabuf_put_str(buf, soap_postfix); } os_free(replydata); /* Now patch in the content length at the end */ if (body_start && put_length_here) { int body_length = (char *) wpabuf_put(buf, 0) - body_start; char len_buf[10]; os_snprintf(len_buf, sizeof(len_buf), "%d", body_length); os_memcpy(put_length_here, len_buf, os_strlen(len_buf)); } http_request_send_and_deinit(req, buf); }
/* event_send_tx_ready -- actually write event message * * Prequisite: subscription socket descriptor has become ready to * write (because connection to subscriber has been made). * * It is also possible that we are called because the connect has failed; * it is possible to test for this, or we can just go ahead and then * the write will fail. */ static void event_send_tx_ready(int sock, void *eloop_ctx, void *sock_ctx) { struct wps_event_ *e = sock_ctx; struct subscription *s = e->s; struct wpabuf *buf; char *b; assert(e == s->current_event); assert(e->sd == sock); buf = wpabuf_alloc(1000 + wpabuf_len(e->data)); if (buf == NULL) { event_retry(e, 0); goto bad; } wpabuf_printf(buf, "NOTIFY %s HTTP/1.1\r\n", e->addr->path); wpabuf_put_str(buf, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n"); wpabuf_printf(buf, "HOST: %s\r\n", e->addr->domain_and_port); wpabuf_put_str(buf, "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n" "NT: upnp:event\r\n" "NTS: upnp:propchange\r\n"); wpabuf_put_str(buf, "SID: uuid:"); b = wpabuf_put(buf, 0); uuid_bin2str(s->uuid, b, 80); wpabuf_put(buf, os_strlen(b)); wpabuf_put_str(buf, "\r\n"); wpabuf_printf(buf, "SEQ: %u\r\n", e->subscriber_sequence); wpabuf_printf(buf, "CONTENT-LENGTH: %d\r\n", (int) wpabuf_len(e->data)); wpabuf_put_str(buf, "\r\n"); /* terminating empty line */ wpabuf_put_buf(buf, e->data); /* Since the message size is pretty small, we should be * able to get the operating system to buffer what we give it * and not have to come back again later to write more... */ #if 0 /* we could: Turn blocking back on? */ fcntl(e->sd, F_SETFL, 0); #endif wpa_printf(MSG_DEBUG, "WPS UPnP: Sending event to %s", e->addr->domain_and_port); if (send_wpabuf(e->sd, buf) < 0) { event_retry(e, 1); goto bad; } wpabuf_free(buf); buf = NULL; if (e->sd_registered) { e->sd_registered = 0; eloop_unregister_sock(e->sd, EVENT_TYPE_WRITE); } /* Set up to read the reply */ e->hread = httpread_create(e->sd, event_got_response_handler, e /* cookie */, 0 /* no data expected */, EVENT_TIMEOUT_SEC); if (e->hread == NULL) { wpa_printf(MSG_ERROR, "WPS UPnP: httpread_create failed"); event_retry(e, 0); goto bad; } return; bad: /* Schedule sending more if there is more to send */ if (s->event_queue) event_send_all_later(s->sm); wpabuf_free(buf); }
/* xml_add_tagged_data -- format tagged data as a new xml line. * * tag must not have any special chars. * data may have special chars, which are escaped. */ void xml_add_tagged_data(struct wpabuf *buf, const char *tag, const char *data) { wpabuf_printf(buf, "<%s>", tag); xml_data_encode(buf, data, os_strlen(data)); wpabuf_printf(buf, "</%s>\n", tag); }