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