00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "includes.h"
00012
00013 #include "common.h"
00014 #include "base64.h"
00015 #include "uuid.h"
00016 #include "httpread.h"
00017 #include "http_server.h"
00018 #include "wps_i.h"
00019 #include "wps_upnp.h"
00020 #include "wps_upnp_i.h"
00021 #include "upnp_xml.h"
00022
00023
00024
00025
00026
00027
00028 #define WEB_CONNECTION_TIMEOUT_SEC 30
00029 #define WEB_CONNECTION_MAX_READ 8000
00030 #define MAX_WEB_CONNECTIONS 10
00031
00032
00033 static const char *urn_wfawlanconfig =
00034 "urn:schemas-wifialliance-org:service:WFAWLANConfig:1";
00035 static const char *http_server_hdr =
00036 "Server: unspecified, UPnP/1.0, unspecified\r\n";
00037 static const char *http_connection_close =
00038 "Connection: close\r\n";
00039
00040
00041
00042
00043
00044
00045 static const char wps_scpd_xml[] =
00046 "<?xml version=\"1.0\"?>\n"
00047 "<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">\n"
00048 "<specVersion><major>1</major><minor>0</minor></specVersion>\n"
00049 "<actionList>\n"
00050 "<action>\n"
00051 "<name>GetDeviceInfo</name>\n"
00052 "<argumentList>\n"
00053 "<argument>\n"
00054 "<name>NewDeviceInfo</name>\n"
00055 "<direction>out</direction>\n"
00056 "<relatedStateVariable>DeviceInfo</relatedStateVariable>\n"
00057 "</argument>\n"
00058 "</argumentList>\n"
00059 "</action>\n"
00060 "<action>\n"
00061 "<name>PutMessage</name>\n"
00062 "<argumentList>\n"
00063 "<argument>\n"
00064 "<name>NewInMessage</name>\n"
00065 "<direction>in</direction>\n"
00066 "<relatedStateVariable>InMessage</relatedStateVariable>\n"
00067 "</argument>\n"
00068 "<argument>\n"
00069 "<name>NewOutMessage</name>\n"
00070 "<direction>out</direction>\n"
00071 "<relatedStateVariable>OutMessage</relatedStateVariable>\n"
00072 "</argument>\n"
00073 "</argumentList>\n"
00074 "</action>\n"
00075 "<action>\n"
00076 "<name>PutWLANResponse</name>\n"
00077 "<argumentList>\n"
00078 "<argument>\n"
00079 "<name>NewMessage</name>\n"
00080 "<direction>in</direction>\n"
00081 "<relatedStateVariable>Message</relatedStateVariable>\n"
00082 "</argument>\n"
00083 "<argument>\n"
00084 "<name>NewWLANEventType</name>\n"
00085 "<direction>in</direction>\n"
00086 "<relatedStateVariable>WLANEventType</relatedStateVariable>\n"
00087 "</argument>\n"
00088 "<argument>\n"
00089 "<name>NewWLANEventMAC</name>\n"
00090 "<direction>in</direction>\n"
00091 "<relatedStateVariable>WLANEventMAC</relatedStateVariable>\n"
00092 "</argument>\n"
00093 "</argumentList>\n"
00094 "</action>\n"
00095 "<action>\n"
00096 "<name>SetSelectedRegistrar</name>\n"
00097 "<argumentList>\n"
00098 "<argument>\n"
00099 "<name>NewMessage</name>\n"
00100 "<direction>in</direction>\n"
00101 "<relatedStateVariable>Message</relatedStateVariable>\n"
00102 "</argument>\n"
00103 "</argumentList>\n"
00104 "</action>\n"
00105 "</actionList>\n"
00106 "<serviceStateTable>\n"
00107 "<stateVariable sendEvents=\"no\">\n"
00108 "<name>Message</name>\n"
00109 "<dataType>bin.base64</dataType>\n"
00110 "</stateVariable>\n"
00111 "<stateVariable sendEvents=\"no\">\n"
00112 "<name>InMessage</name>\n"
00113 "<dataType>bin.base64</dataType>\n"
00114 "</stateVariable>\n"
00115 "<stateVariable sendEvents=\"no\">\n"
00116 "<name>OutMessage</name>\n"
00117 "<dataType>bin.base64</dataType>\n"
00118 "</stateVariable>\n"
00119 "<stateVariable sendEvents=\"no\">\n"
00120 "<name>DeviceInfo</name>\n"
00121 "<dataType>bin.base64</dataType>\n"
00122 "</stateVariable>\n"
00123 "<stateVariable sendEvents=\"yes\">\n"
00124 "<name>APStatus</name>\n"
00125 "<dataType>ui1</dataType>\n"
00126 "</stateVariable>\n"
00127 "<stateVariable sendEvents=\"yes\">\n"
00128 "<name>STAStatus</name>\n"
00129 "<dataType>ui1</dataType>\n"
00130 "</stateVariable>\n"
00131 "<stateVariable sendEvents=\"yes\">\n"
00132 "<name>WLANEvent</name>\n"
00133 "<dataType>bin.base64</dataType>\n"
00134 "</stateVariable>\n"
00135 "<stateVariable sendEvents=\"no\">\n"
00136 "<name>WLANEventType</name>\n"
00137 "<dataType>ui1</dataType>\n"
00138 "</stateVariable>\n"
00139 "<stateVariable sendEvents=\"no\">\n"
00140 "<name>WLANEventMAC</name>\n"
00141 "<dataType>string</dataType>\n"
00142 "</stateVariable>\n"
00143 "<stateVariable sendEvents=\"no\">\n"
00144 "<name>WLANResponse</name>\n"
00145 "<dataType>bin.base64</dataType>\n"
00146 "</stateVariable>\n"
00147 "</serviceStateTable>\n"
00148 "</scpd>\n"
00149 ;
00150
00151
00152 static const char *wps_device_xml_prefix =
00153 "<?xml version=\"1.0\"?>\n"
00154 "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n"
00155 "<specVersion>\n"
00156 "<major>1</major>\n"
00157 "<minor>0</minor>\n"
00158 "</specVersion>\n"
00159 "<device>\n"
00160 "<deviceType>urn:schemas-wifialliance-org:device:WFADevice:1"
00161 "</deviceType>\n";
00162
00163 static const char *wps_device_xml_postfix =
00164 "<serviceList>\n"
00165 "<service>\n"
00166 "<serviceType>urn:schemas-wifialliance-org:service:WFAWLANConfig:1"
00167 "</serviceType>\n"
00168 "<serviceId>urn:wifialliance-org:serviceId:WFAWLANConfig1</serviceId>"
00169 "\n"
00170 "<SCPDURL>" UPNP_WPS_SCPD_XML_FILE "</SCPDURL>\n"
00171 "<controlURL>" UPNP_WPS_DEVICE_CONTROL_FILE "</controlURL>\n"
00172 "<eventSubURL>" UPNP_WPS_DEVICE_EVENT_FILE "</eventSubURL>\n"
00173 "</service>\n"
00174 "</serviceList>\n"
00175 "</device>\n"
00176 "</root>\n";
00177
00178
00179
00180
00181
00182 static void format_wps_device_xml(struct upnp_wps_device_sm *sm,
00183 struct wpabuf *buf)
00184 {
00185 const char *s;
00186 char uuid_string[80];
00187
00188 wpabuf_put_str(buf, wps_device_xml_prefix);
00189
00190
00191
00192
00193
00194 s = sm->wps->friendly_name;
00195 s = ((s && *s) ? s : "WPS Access Point");
00196 xml_add_tagged_data(buf, "friendlyName", s);
00197
00198 s = sm->wps->dev.manufacturer;
00199 s = ((s && *s) ? s : "");
00200 xml_add_tagged_data(buf, "manufacturer", s);
00201
00202 if (sm->wps->manufacturer_url)
00203 xml_add_tagged_data(buf, "manufacturerURL",
00204 sm->wps->manufacturer_url);
00205
00206 if (sm->wps->model_description)
00207 xml_add_tagged_data(buf, "modelDescription",
00208 sm->wps->model_description);
00209
00210 s = sm->wps->dev.model_name;
00211 s = ((s && *s) ? s : "");
00212 xml_add_tagged_data(buf, "modelName", s);
00213
00214 if (sm->wps->dev.model_number)
00215 xml_add_tagged_data(buf, "modelNumber",
00216 sm->wps->dev.model_number);
00217
00218 if (sm->wps->model_url)
00219 xml_add_tagged_data(buf, "modelURL", sm->wps->model_url);
00220
00221 if (sm->wps->dev.serial_number)
00222 xml_add_tagged_data(buf, "serialNumber",
00223 sm->wps->dev.serial_number);
00224
00225 uuid_bin2str(sm->wps->uuid, uuid_string, sizeof(uuid_string));
00226 s = uuid_string;
00227
00228
00229
00230 wpabuf_put_str(buf, "<UDN>uuid:");
00231 xml_data_encode(buf, s, os_strlen(s));
00232 wpabuf_put_str(buf, "</UDN>\n");
00233
00234 if (sm->wps->upc)
00235 xml_add_tagged_data(buf, "UPC", sm->wps->upc);
00236
00237 wpabuf_put_str(buf, wps_device_xml_postfix);
00238 }
00239
00240
00241 static void http_put_reply_code(struct wpabuf *buf, enum http_reply_code code)
00242 {
00243 wpabuf_put_str(buf, "HTTP/1.1 ");
00244 switch (code) {
00245 case HTTP_OK:
00246 wpabuf_put_str(buf, "200 OK\r\n");
00247 break;
00248 case HTTP_BAD_REQUEST:
00249 wpabuf_put_str(buf, "400 Bad request\r\n");
00250 break;
00251 case HTTP_PRECONDITION_FAILED:
00252 wpabuf_put_str(buf, "412 Precondition failed\r\n");
00253 break;
00254 case HTTP_UNIMPLEMENTED:
00255 wpabuf_put_str(buf, "501 Unimplemented\r\n");
00256 break;
00257 case HTTP_INTERNAL_SERVER_ERROR:
00258 default:
00259 wpabuf_put_str(buf, "500 Internal server error\r\n");
00260 break;
00261 }
00262 }
00263
00264
00265 static void http_put_date(struct wpabuf *buf)
00266 {
00267 wpabuf_put_str(buf, "Date: ");
00268 format_date(buf);
00269 wpabuf_put_str(buf, "\r\n");
00270 }
00271
00272
00273 static void http_put_empty(struct wpabuf *buf, enum http_reply_code code)
00274 {
00275 http_put_reply_code(buf, code);
00276 wpabuf_put_str(buf, http_server_hdr);
00277 wpabuf_put_str(buf, http_connection_close);
00278 wpabuf_put_str(buf, "Content-Length: 0\r\n"
00279 "\r\n");
00280 }
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301 static void web_connection_parse_get(struct upnp_wps_device_sm *sm,
00302 struct http_request *hreq, char *filename)
00303 {
00304 struct wpabuf *buf;
00305 char *put_length_here;
00306 char *body_start;
00307 enum {
00308 GET_DEVICE_XML_FILE,
00309 GET_SCPD_XML_FILE
00310 } req;
00311 size_t extra_len = 0;
00312 int body_length;
00313 char len_buf[10];
00314
00315
00316
00317
00318
00319 if (filename == NULL)
00320 filename = "(null)";
00321 if (os_strcasecmp(filename, UPNP_WPS_DEVICE_XML_FILE) == 0) {
00322 wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for device XML");
00323 req = GET_DEVICE_XML_FILE;
00324 extra_len = 3000;
00325 if (sm->wps->friendly_name)
00326 extra_len += os_strlen(sm->wps->friendly_name);
00327 if (sm->wps->manufacturer_url)
00328 extra_len += os_strlen(sm->wps->manufacturer_url);
00329 if (sm->wps->model_description)
00330 extra_len += os_strlen(sm->wps->model_description);
00331 if (sm->wps->model_url)
00332 extra_len += os_strlen(sm->wps->model_url);
00333 if (sm->wps->upc)
00334 extra_len += os_strlen(sm->wps->upc);
00335 } else if (!os_strcasecmp(filename, UPNP_WPS_SCPD_XML_FILE)) {
00336 wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for SCPD XML");
00337 req = GET_SCPD_XML_FILE;
00338 extra_len = os_strlen(wps_scpd_xml);
00339 } else {
00340
00341 wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET file not found: %s",
00342 filename);
00343 buf = wpabuf_alloc(200);
00344 if (buf == NULL) {
00345 http_request_deinit(hreq);
00346 return;
00347 }
00348 wpabuf_put_str(buf,
00349 "HTTP/1.1 404 Not Found\r\n"
00350 "Connection: close\r\n");
00351
00352 http_put_date(buf);
00353
00354
00355 wpabuf_put_str(buf, "\r\n");
00356
00357 goto send_buf;
00358 }
00359
00360 buf = wpabuf_alloc(1000 + extra_len);
00361 if (buf == NULL) {
00362 http_request_deinit(hreq);
00363 return;
00364 }
00365
00366 wpabuf_put_str(buf,
00367 "HTTP/1.1 200 OK\r\n"
00368 "Content-Type: text/xml; charset=\"utf-8\"\r\n");
00369 wpabuf_put_str(buf, "Server: Unspecified, UPnP/1.0, Unspecified\r\n");
00370 wpabuf_put_str(buf, "Connection: close\r\n");
00371 wpabuf_put_str(buf, "Content-Length: ");
00372
00373
00374
00375
00376 put_length_here = wpabuf_put(buf, 0);
00377 wpabuf_put_str(buf, " \r\n");
00378
00379 http_put_date(buf);
00380
00381
00382 wpabuf_put_str(buf, "\r\n");
00383
00384 body_start = wpabuf_put(buf, 0);
00385
00386 switch (req) {
00387 case GET_DEVICE_XML_FILE:
00388 format_wps_device_xml(sm, buf);
00389 break;
00390 case GET_SCPD_XML_FILE:
00391 wpabuf_put_str(buf, wps_scpd_xml);
00392 break;
00393 }
00394
00395
00396 body_length = (char *) wpabuf_put(buf, 0) - body_start;
00397 os_snprintf(len_buf, 10, "%d", body_length);
00398 os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
00399
00400 send_buf:
00401 http_request_send_and_deinit(hreq, buf);
00402 }
00403
00404
00405 static enum http_reply_code
00406 web_process_get_device_info(struct upnp_wps_device_sm *sm,
00407 struct wpabuf **reply, const char **replyname)
00408 {
00409 static const char *name = "NewDeviceInfo";
00410 struct wps_config cfg;
00411 struct upnp_wps_peer *peer = &sm->peer;
00412
00413 wpa_printf(MSG_DEBUG, "WPS UPnP: GetDeviceInfo");
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423 if (peer->wps)
00424 wps_deinit(peer->wps);
00425
00426 os_memset(&cfg, 0, sizeof(cfg));
00427 cfg.wps = sm->wps;
00428 cfg.pin = (u8 *) sm->ctx->ap_pin;
00429 cfg.pin_len = os_strlen(sm->ctx->ap_pin);
00430 peer->wps = wps_init(&cfg);
00431 if (peer->wps) {
00432 enum wsc_op_code op_code;
00433 *reply = wps_get_msg(peer->wps, &op_code);
00434 if (*reply == NULL) {
00435 wps_deinit(peer->wps);
00436 peer->wps = NULL;
00437 }
00438 } else
00439 *reply = NULL;
00440 if (*reply == NULL) {
00441 wpa_printf(MSG_INFO, "WPS UPnP: Failed to get DeviceInfo");
00442 return HTTP_INTERNAL_SERVER_ERROR;
00443 }
00444 *replyname = name;
00445 return HTTP_OK;
00446 }
00447
00448
00449 static enum http_reply_code
00450 web_process_put_message(struct upnp_wps_device_sm *sm, char *data,
00451 struct wpabuf **reply, const char **replyname)
00452 {
00453 struct wpabuf *msg;
00454 static const char *name = "NewOutMessage";
00455 enum http_reply_code ret;
00456 enum wps_process_res res;
00457 enum wsc_op_code op_code;
00458
00459
00460
00461
00462
00463
00464 wpa_printf(MSG_DEBUG, "WPS UPnP: PutMessage");
00465 msg = xml_get_base64_item(data, "NewInMessage", &ret);
00466 if (msg == NULL)
00467 return ret;
00468 res = wps_process_msg(sm->peer.wps, WSC_UPnP, msg);
00469 if (res == WPS_FAILURE)
00470 *reply = NULL;
00471 else
00472 *reply = wps_get_msg(sm->peer.wps, &op_code);
00473 wpabuf_free(msg);
00474 if (*reply == NULL)
00475 return HTTP_INTERNAL_SERVER_ERROR;
00476 *replyname = name;
00477 return HTTP_OK;
00478 }
00479
00480
00481 static enum http_reply_code
00482 web_process_put_wlan_response(struct upnp_wps_device_sm *sm, char *data,
00483 struct wpabuf **reply, const char **replyname)
00484 {
00485 struct wpabuf *msg;
00486 enum http_reply_code ret;
00487 u8 macaddr[ETH_ALEN];
00488 int ev_type;
00489 int type;
00490 char *val;
00491
00492
00493
00494
00495
00496
00497 wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse");
00498 msg = xml_get_base64_item(data, "NewMessage", &ret);
00499 if (msg == NULL) {
00500 wpa_printf(MSG_DEBUG, "WPS UPnP: Could not extract NewMessage "
00501 "from PutWLANResponse");
00502 return ret;
00503 }
00504 val = xml_get_first_item(data, "NewWLANEventType");
00505 if (val == NULL) {
00506 wpa_printf(MSG_DEBUG, "WPS UPnP: No NewWLANEventType in "
00507 "PutWLANResponse");
00508 wpabuf_free(msg);
00509 return UPNP_ARG_VALUE_INVALID;
00510 }
00511 ev_type = atol(val);
00512 os_free(val);
00513 val = xml_get_first_item(data, "NewWLANEventMAC");
00514 if (val == NULL) {
00515 wpa_printf(MSG_DEBUG, "WPS UPnP: No NewWLANEventMAC in "
00516 "PutWLANResponse");
00517 wpabuf_free(msg);
00518 return UPNP_ARG_VALUE_INVALID;
00519 }
00520 if (hwaddr_aton(val, macaddr)) {
00521 wpa_printf(MSG_DEBUG, "WPS UPnP: Invalid NewWLANEventMAC in "
00522 "PutWLANResponse: '%s'", val);
00523 if (hwaddr_aton2(val, macaddr) > 0) {
00524
00525
00526
00527
00528 wpa_printf(MSG_DEBUG, "WPS UPnP: Workaround - allow "
00529 "incorrect MAC address format in "
00530 "NewWLANEventMAC");
00531 } else {
00532 wpabuf_free(msg);
00533 os_free(val);
00534 return UPNP_ARG_VALUE_INVALID;
00535 }
00536 }
00537 os_free(val);
00538 if (ev_type == UPNP_WPS_WLANEVENT_TYPE_EAP) {
00539 struct wps_parse_attr attr;
00540 if (wps_parse_msg(msg, &attr) < 0 ||
00541 attr.msg_type == NULL)
00542 type = -1;
00543 else
00544 type = *attr.msg_type;
00545 wpa_printf(MSG_DEBUG, "WPS UPnP: Message Type %d", type);
00546 } else
00547 type = -1;
00548 if (!sm->ctx->rx_req_put_wlan_response ||
00549 sm->ctx->rx_req_put_wlan_response(sm->priv, ev_type, macaddr, msg,
00550 type)) {
00551 wpa_printf(MSG_INFO, "WPS UPnP: Fail: sm->ctx->"
00552 "rx_req_put_wlan_response");
00553 wpabuf_free(msg);
00554 return HTTP_INTERNAL_SERVER_ERROR;
00555 }
00556 wpabuf_free(msg);
00557 *replyname = NULL;
00558 *reply = NULL;
00559 return HTTP_OK;
00560 }
00561
00562
00563 static int find_er_addr(struct subscription *s, struct sockaddr_in *cli)
00564 {
00565 struct subscr_addr *a;
00566
00567 dl_list_for_each(a, &s->addr_list, struct subscr_addr, list) {
00568 if (cli->sin_addr.s_addr == a->saddr.sin_addr.s_addr)
00569 return 1;
00570 }
00571 return 0;
00572 }
00573
00574
00575 static struct subscription * find_er(struct upnp_wps_device_sm *sm,
00576 struct sockaddr_in *cli)
00577 {
00578 struct subscription *s;
00579 dl_list_for_each(s, &sm->subscriptions, struct subscription, list)
00580 if (find_er_addr(s, cli))
00581 return s;
00582 return NULL;
00583 }
00584
00585
00586 static enum http_reply_code
00587 web_process_set_selected_registrar(struct upnp_wps_device_sm *sm,
00588 struct sockaddr_in *cli, char *data,
00589 struct wpabuf **reply,
00590 const char **replyname)
00591 {
00592 struct wpabuf *msg;
00593 enum http_reply_code ret;
00594 struct subscription *s;
00595
00596 wpa_printf(MSG_DEBUG, "WPS UPnP: SetSelectedRegistrar");
00597 s = find_er(sm, cli);
00598 if (s == NULL) {
00599 wpa_printf(MSG_DEBUG, "WPS UPnP: Ignore SetSelectedRegistrar "
00600 "from unknown ER");
00601 return UPNP_ACTION_FAILED;
00602 }
00603 msg = xml_get_base64_item(data, "NewMessage", &ret);
00604 if (msg == NULL)
00605 return ret;
00606 if (upnp_er_set_selected_registrar(sm->wps->registrar, s, msg)) {
00607 wpabuf_free(msg);
00608 return HTTP_INTERNAL_SERVER_ERROR;
00609 }
00610 wpabuf_free(msg);
00611 *replyname = NULL;
00612 *reply = NULL;
00613 return HTTP_OK;
00614 }
00615
00616
00617 static const char *soap_prefix =
00618 "<?xml version=\"1.0\"?>\n"
00619 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
00620 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
00621 "<s:Body>\n";
00622 static const char *soap_postfix =
00623 "</s:Body>\n</s:Envelope>\n";
00624
00625 static const char *soap_error_prefix =
00626 "<s:Fault>\n"
00627 "<faultcode>s:Client</faultcode>\n"
00628 "<faultstring>UPnPError</faultstring>\n"
00629 "<detail>\n"
00630 "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">\n";
00631 static const char *soap_error_postfix =
00632 "<errorDescription>Error</errorDescription>\n"
00633 "</UPnPError>\n"
00634 "</detail>\n"
00635 "</s:Fault>\n";
00636
00637 static void web_connection_send_reply(struct http_request *req,
00638 enum http_reply_code ret,
00639 const char *action, int action_len,
00640 const struct wpabuf *reply,
00641 const char *replyname)
00642 {
00643 struct wpabuf *buf;
00644 char *replydata;
00645 char *put_length_here = NULL;
00646 char *body_start = NULL;
00647
00648 if (reply) {
00649 size_t len;
00650 replydata = (char *) base64_encode(wpabuf_head(reply),
00651 wpabuf_len(reply), &len);
00652 } else
00653 replydata = NULL;
00654
00655
00656
00657
00658
00659
00660 buf = wpabuf_alloc(1000 + (replydata ? os_strlen(replydata) : 0U) +
00661 (action_len > 0 ? action_len * 2 : 0));
00662 if (buf == NULL) {
00663 wpa_printf(MSG_INFO, "WPS UPnP: Cannot allocate reply to "
00664 "POST");
00665 os_free(replydata);
00666 http_request_deinit(req);
00667 return;
00668 }
00669
00670
00671
00672
00673
00674
00675 if (ret == HTTP_OK) {
00676 wpabuf_put_str(buf,
00677 "HTTP/1.1 200 OK\r\n"
00678 "Content-Type: text/xml; "
00679 "charset=\"utf-8\"\r\n");
00680 } else {
00681 wpabuf_printf(buf, "HTTP/1.1 %d Error\r\n", ret);
00682 }
00683 wpabuf_put_str(buf, http_connection_close);
00684
00685 wpabuf_put_str(buf, "Content-Length: ");
00686
00687
00688
00689
00690 put_length_here = wpabuf_put(buf, 0);
00691 wpabuf_put_str(buf, " \r\n");
00692
00693 http_put_date(buf);
00694
00695
00696 wpabuf_put_str(buf, "\r\n");
00697
00698 body_start = wpabuf_put(buf, 0);
00699
00700 if (ret == HTTP_OK) {
00701 wpabuf_put_str(buf, soap_prefix);
00702 wpabuf_put_str(buf, "<u:");
00703 wpabuf_put_data(buf, action, action_len);
00704 wpabuf_put_str(buf, "Response xmlns:u=\"");
00705 wpabuf_put_str(buf, urn_wfawlanconfig);
00706 wpabuf_put_str(buf, "\">\n");
00707 if (replydata && replyname) {
00708
00709
00710
00711
00712
00713 wpabuf_printf(buf, "<%s>", replyname);
00714 wpabuf_put_str(buf, replydata);
00715 wpabuf_printf(buf, "</%s>\n", replyname);
00716 }
00717 wpabuf_put_str(buf, "</u:");
00718 wpabuf_put_data(buf, action, action_len);
00719 wpabuf_put_str(buf, "Response>\n");
00720 wpabuf_put_str(buf, soap_postfix);
00721 } else {
00722
00723 wpabuf_put_str(buf, soap_prefix);
00724 wpabuf_put_str(buf, soap_error_prefix);
00725 wpabuf_printf(buf, "<errorCode>%d</errorCode>\n", ret);
00726 wpabuf_put_str(buf, soap_error_postfix);
00727 wpabuf_put_str(buf, soap_postfix);
00728 }
00729 os_free(replydata);
00730
00731
00732 if (body_start && put_length_here) {
00733 int body_length = (char *) wpabuf_put(buf, 0) - body_start;
00734 char len_buf[10];
00735 os_snprintf(len_buf, sizeof(len_buf), "%d", body_length);
00736 os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
00737 }
00738
00739 http_request_send_and_deinit(req, buf);
00740 }
00741
00742
00743 static const char * web_get_action(struct http_request *req,
00744 size_t *action_len)
00745 {
00746 const char *match;
00747 int match_len;
00748 char *b;
00749 char *action;
00750
00751 *action_len = 0;
00752
00753 b = http_request_get_hdr_line(req, "SOAPAction:");
00754 if (b == NULL)
00755 return NULL;
00756 if (*b == '"')
00757 b++;
00758 else
00759 return NULL;
00760 match = urn_wfawlanconfig;
00761 match_len = os_strlen(urn_wfawlanconfig) - 1;
00762 if (os_strncasecmp(b, match, match_len))
00763 return NULL;
00764 b += match_len;
00765
00766 while (isgraph(*b) && *b != '#')
00767 b++;
00768 if (*b != '#')
00769 return NULL;
00770 b++;
00771
00772 action = b;
00773 while (isgraph(*b) && *b != '"')
00774 b++;
00775 if (*b != '"')
00776 return NULL;
00777 *action_len = b - action;
00778 return action;
00779 }
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800 static void web_connection_parse_post(struct upnp_wps_device_sm *sm,
00801 struct sockaddr_in *cli,
00802 struct http_request *req,
00803 const char *filename)
00804 {
00805 enum http_reply_code ret;
00806 char *data = http_request_get_data(req);
00807 const char *action = NULL;
00808 size_t action_len = 0;
00809 const char *replyname = NULL;
00810 struct wpabuf *reply = NULL;
00811
00812 if (os_strcasecmp(filename, UPNP_WPS_DEVICE_CONTROL_FILE)) {
00813 wpa_printf(MSG_INFO, "WPS UPnP: Invalid POST filename %s",
00814 filename);
00815 ret = HTTP_NOT_FOUND;
00816 goto bad;
00817 }
00818
00819 ret = UPNP_INVALID_ACTION;
00820 action = web_get_action(req, &action_len);
00821 if (action == NULL)
00822 goto bad;
00823
00824 if (!os_strncasecmp("GetDeviceInfo", action, action_len))
00825 ret = web_process_get_device_info(sm, &reply, &replyname);
00826 else if (!os_strncasecmp("PutMessage", action, action_len))
00827 ret = web_process_put_message(sm, data, &reply, &replyname);
00828 else if (!os_strncasecmp("PutWLANResponse", action, action_len))
00829 ret = web_process_put_wlan_response(sm, data, &reply,
00830 &replyname);
00831 else if (!os_strncasecmp("SetSelectedRegistrar", action, action_len))
00832 ret = web_process_set_selected_registrar(sm, cli, data, &reply,
00833 &replyname);
00834 else
00835 wpa_printf(MSG_INFO, "WPS UPnP: Unknown POST type");
00836
00837 bad:
00838 if (ret != HTTP_OK)
00839 wpa_printf(MSG_INFO, "WPS UPnP: POST failure ret=%d", ret);
00840 web_connection_send_reply(req, ret, action, action_len, reply,
00841 replyname);
00842 wpabuf_free(reply);
00843 }
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865 static void web_connection_parse_subscribe(struct upnp_wps_device_sm *sm,
00866 struct http_request *req,
00867 const char *filename)
00868 {
00869 struct wpabuf *buf;
00870 char *b;
00871 char *hdr = http_request_get_hdr(req);
00872 char *h;
00873 char *match;
00874 int match_len;
00875 char *end;
00876 int len;
00877 int got_nt = 0;
00878 u8 uuid[UUID_LEN];
00879 int got_uuid = 0;
00880 char *callback_urls = NULL;
00881 struct subscription *s = NULL;
00882 enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR;
00883
00884 buf = wpabuf_alloc(1000);
00885 if (buf == NULL) {
00886 http_request_deinit(req);
00887 return;
00888 }
00889
00890
00891 h = hdr;
00892
00893
00894
00895 if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) {
00896 ret = HTTP_PRECONDITION_FAILED;
00897 goto error;
00898 }
00899 wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP SUBSCRIBE for event");
00900 end = os_strchr(h, '\n');
00901
00902 for (; end != NULL; h = end + 1) {
00903
00904 h = end + 1;
00905 end = os_strchr(h, '\n');
00906 if (end == NULL)
00907 break;
00908
00909
00910
00911
00912 match = "NT:";
00913 match_len = os_strlen(match);
00914 if (os_strncasecmp(h, match, match_len) == 0) {
00915 h += match_len;
00916 while (*h == ' ' || *h == '\t')
00917 h++;
00918 match = "upnp:event";
00919 match_len = os_strlen(match);
00920 if (os_strncasecmp(h, match, match_len) != 0) {
00921 ret = HTTP_BAD_REQUEST;
00922 goto error;
00923 }
00924 got_nt = 1;
00925 continue;
00926 }
00927
00928 #if 0
00929 match = "HOST:";
00930 match_len = os_strlen(match);
00931 if (os_strncasecmp(h, match, match_len) == 0) {
00932 h += match_len;
00933 while (*h == ' ' || *h == '\t')
00934 h++;
00935 .....
00936 }
00937 #endif
00938
00939
00940
00941
00942 match = "CALLBACK:";
00943 match_len = os_strlen(match);
00944 if (os_strncasecmp(h, match, match_len) == 0) {
00945 h += match_len;
00946 while (*h == ' ' || *h == '\t')
00947 h++;
00948 len = end - h;
00949 os_free(callback_urls);
00950 callback_urls = os_malloc(len + 1);
00951 if (callback_urls == NULL) {
00952 ret = HTTP_INTERNAL_SERVER_ERROR;
00953 goto error;
00954 }
00955 os_memcpy(callback_urls, h, len);
00956 callback_urls[len] = 0;
00957 continue;
00958 }
00959
00960 match = "SID:";
00961 match_len = os_strlen(match);
00962 if (os_strncasecmp(h, match, match_len) == 0) {
00963 h += match_len;
00964 while (*h == ' ' || *h == '\t')
00965 h++;
00966 match = "uuid:";
00967 match_len = os_strlen(match);
00968 if (os_strncasecmp(h, match, match_len) != 0) {
00969 ret = HTTP_BAD_REQUEST;
00970 goto error;
00971 }
00972 h += match_len;
00973 while (*h == ' ' || *h == '\t')
00974 h++;
00975 if (uuid_str2bin(h, uuid)) {
00976 ret = HTTP_BAD_REQUEST;
00977 goto error;
00978 }
00979 got_uuid = 1;
00980 continue;
00981 }
00982
00983
00984
00985 }
00986
00987 if (got_uuid) {
00988
00989 if (callback_urls) {
00990 ret = HTTP_BAD_REQUEST;
00991 goto error;
00992 }
00993 s = subscription_renew(sm, uuid);
00994 if (s == NULL) {
00995 ret = HTTP_PRECONDITION_FAILED;
00996 goto error;
00997 }
00998 } else if (callback_urls) {
00999 if (!got_nt) {
01000 ret = HTTP_PRECONDITION_FAILED;
01001 goto error;
01002 }
01003 s = subscription_start(sm, callback_urls);
01004 if (s == NULL) {
01005 ret = HTTP_INTERNAL_SERVER_ERROR;
01006 goto error;
01007 }
01008 } else {
01009 ret = HTTP_PRECONDITION_FAILED;
01010 goto error;
01011 }
01012
01013
01014 http_put_reply_code(buf, HTTP_OK);
01015 wpabuf_put_str(buf, http_server_hdr);
01016 wpabuf_put_str(buf, http_connection_close);
01017 wpabuf_put_str(buf, "Content-Length: 0\r\n");
01018 wpabuf_put_str(buf, "SID: uuid:");
01019
01020 b = wpabuf_put(buf, 0);
01021 uuid_bin2str(s->uuid, b, 80);
01022 wpabuf_put(buf, os_strlen(b));
01023 wpabuf_put_str(buf, "\r\n");
01024 wpabuf_printf(buf, "Timeout: Second-%d\r\n", UPNP_SUBSCRIBE_SEC);
01025 http_put_date(buf);
01026
01027 wpabuf_put_str(buf, "\r\n");
01028
01029 os_free(callback_urls);
01030 http_request_send_and_deinit(req, buf);
01031 return;
01032
01033 error:
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055 http_put_empty(buf, ret);
01056 http_request_send_and_deinit(req, buf);
01057 os_free(callback_urls);
01058 }
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076 static void web_connection_parse_unsubscribe(struct upnp_wps_device_sm *sm,
01077 struct http_request *req,
01078 const char *filename)
01079 {
01080 struct wpabuf *buf;
01081 char *hdr = http_request_get_hdr(req);
01082 char *h;
01083 char *match;
01084 int match_len;
01085 char *end;
01086 u8 uuid[UUID_LEN];
01087 int got_uuid = 0;
01088 struct subscription *s = NULL;
01089 enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR;
01090
01091
01092 h = hdr;
01093
01094
01095
01096 if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) {
01097 ret = HTTP_PRECONDITION_FAILED;
01098 goto send_msg;
01099 }
01100 wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP UNSUBSCRIBE for event");
01101 end = os_strchr(h, '\n');
01102
01103 for (; end != NULL; h = end + 1) {
01104
01105 h = end + 1;
01106 end = os_strchr(h, '\n');
01107 if (end == NULL)
01108 break;
01109
01110
01111 #if 0
01112 match = "HOST:";
01113 match_len = os_strlen(match);
01114 if (os_strncasecmp(h, match, match_len) == 0) {
01115 h += match_len;
01116 while (*h == ' ' || *h == '\t')
01117 h++;
01118 .....
01119 }
01120 #endif
01121
01122 match = "SID:";
01123 match_len = os_strlen(match);
01124 if (os_strncasecmp(h, match, match_len) == 0) {
01125 h += match_len;
01126 while (*h == ' ' || *h == '\t')
01127 h++;
01128 match = "uuid:";
01129 match_len = os_strlen(match);
01130 if (os_strncasecmp(h, match, match_len) != 0) {
01131 ret = HTTP_BAD_REQUEST;
01132 goto send_msg;
01133 }
01134 h += match_len;
01135 while (*h == ' ' || *h == '\t')
01136 h++;
01137 if (uuid_str2bin(h, uuid)) {
01138 ret = HTTP_BAD_REQUEST;
01139 goto send_msg;
01140 }
01141 got_uuid = 1;
01142 continue;
01143 }
01144 }
01145
01146 if (got_uuid) {
01147 s = subscription_find(sm, uuid);
01148 if (s) {
01149 struct subscr_addr *sa;
01150 sa = dl_list_first(&s->addr_list, struct subscr_addr,
01151 list);
01152 wpa_printf(MSG_DEBUG, "WPS UPnP: Unsubscribing %p %s",
01153 s, (sa && sa->domain_and_port) ?
01154 sa->domain_and_port : "-null-");
01155 dl_list_del(&s->list);
01156 subscription_destroy(s);
01157 }
01158 } else {
01159 wpa_printf(MSG_INFO, "WPS UPnP: Unsubscribe fails (not "
01160 "found)");
01161 ret = HTTP_PRECONDITION_FAILED;
01162 goto send_msg;
01163 }
01164
01165 ret = HTTP_OK;
01166
01167 send_msg:
01168 buf = wpabuf_alloc(200);
01169 if (buf == NULL) {
01170 http_request_deinit(req);
01171 return;
01172 }
01173 http_put_empty(buf, ret);
01174 http_request_send_and_deinit(req, buf);
01175 }
01176
01177
01178
01179 static void web_connection_unimplemented(struct http_request *req)
01180 {
01181 struct wpabuf *buf;
01182 buf = wpabuf_alloc(200);
01183 if (buf == NULL) {
01184 http_request_deinit(req);
01185 return;
01186 }
01187 http_put_empty(buf, HTTP_UNIMPLEMENTED);
01188 http_request_send_and_deinit(req, buf);
01189 }
01190
01191
01192
01193
01194
01195 static void web_connection_check_data(void *ctx, struct http_request *req)
01196 {
01197 struct upnp_wps_device_sm *sm = ctx;
01198 enum httpread_hdr_type htype = http_request_get_type(req);
01199 char *filename = http_request_get_uri(req);
01200 struct sockaddr_in *cli = http_request_get_cli_addr(req);
01201
01202 if (!filename) {
01203 wpa_printf(MSG_INFO, "WPS UPnP: Could not get HTTP URI");
01204 http_request_deinit(req);
01205 return;
01206 }
01207
01208 while (*filename == '/')
01209 filename++;
01210
01211 wpa_printf(MSG_DEBUG, "WPS UPnP: Got HTTP request type %d from %s:%d",
01212 htype, inet_ntoa(cli->sin_addr), htons(cli->sin_port));
01213
01214 switch (htype) {
01215 case HTTPREAD_HDR_TYPE_GET:
01216 web_connection_parse_get(sm, req, filename);
01217 break;
01218 case HTTPREAD_HDR_TYPE_POST:
01219 web_connection_parse_post(sm, cli, req, filename);
01220 break;
01221 case HTTPREAD_HDR_TYPE_SUBSCRIBE:
01222 web_connection_parse_subscribe(sm, req, filename);
01223 break;
01224 case HTTPREAD_HDR_TYPE_UNSUBSCRIBE:
01225 web_connection_parse_unsubscribe(sm, req, filename);
01226 break;
01227
01228
01229
01230
01231
01232
01233 default:
01234
01235 web_connection_unimplemented(req);
01236 break;
01237 }
01238 }
01239
01240
01241
01242
01243
01244
01245
01246
01247 void web_listener_stop(struct upnp_wps_device_sm *sm)
01248 {
01249 http_server_deinit(sm->web_srv);
01250 sm->web_srv = NULL;
01251 }
01252
01253
01254 int web_listener_start(struct upnp_wps_device_sm *sm)
01255 {
01256 struct in_addr addr;
01257 addr.s_addr = sm->ip_addr;
01258 sm->web_srv = http_server_init(&addr, -1, web_connection_check_data,
01259 sm);
01260 if (sm->web_srv == NULL) {
01261 web_listener_stop(sm);
01262 return -1;
01263 }
01264 sm->web_port = http_server_get_port(sm->web_srv);
01265
01266 return 0;
01267 }