wps_upnp_web.c 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337
  1. /*
  2. * UPnP WPS Device - Web connections
  3. * Copyright (c) 2000-2003 Intel Corporation
  4. * Copyright (c) 2006-2007 Sony Corporation
  5. * Copyright (c) 2008-2009 Atheros Communications
  6. * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  7. *
  8. * See wps_upnp.c for more details on licensing and code history.
  9. */
  10. #include "includes.h"
  11. #include "common.h"
  12. #include "base64.h"
  13. #include "uuid.h"
  14. #include "httpread.h"
  15. #include "http_server.h"
  16. #include "wps_i.h"
  17. #include "wps_upnp.h"
  18. #include "wps_upnp_i.h"
  19. #include "upnp_xml.h"
  20. /***************************************************************************
  21. * Web connections (we serve pages of info about ourselves, handle
  22. * requests, etc. etc.).
  23. **************************************************************************/
  24. #define WEB_CONNECTION_TIMEOUT_SEC 30 /* Drop web connection after t.o. */
  25. #define WEB_CONNECTION_MAX_READ 8000 /* Max we'll read for TCP request */
  26. #define MAX_WEB_CONNECTIONS 10 /* max simultaneous web connects */
  27. static const char *urn_wfawlanconfig =
  28. "urn:schemas-wifialliance-org:service:WFAWLANConfig:1";
  29. static const char *http_server_hdr =
  30. "Server: unspecified, UPnP/1.0, unspecified\r\n";
  31. static const char *http_connection_close =
  32. "Connection: close\r\n";
  33. /*
  34. * "Files" that we serve via HTTP. The format of these files is given by
  35. * WFA WPS specifications. Extra white space has been removed to save space.
  36. */
  37. static const char wps_scpd_xml[] =
  38. "<?xml version=\"1.0\"?>\n"
  39. "<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">\n"
  40. "<specVersion><major>1</major><minor>0</minor></specVersion>\n"
  41. "<actionList>\n"
  42. "<action>\n"
  43. "<name>GetDeviceInfo</name>\n"
  44. "<argumentList>\n"
  45. "<argument>\n"
  46. "<name>NewDeviceInfo</name>\n"
  47. "<direction>out</direction>\n"
  48. "<relatedStateVariable>DeviceInfo</relatedStateVariable>\n"
  49. "</argument>\n"
  50. "</argumentList>\n"
  51. "</action>\n"
  52. "<action>\n"
  53. "<name>PutMessage</name>\n"
  54. "<argumentList>\n"
  55. "<argument>\n"
  56. "<name>NewInMessage</name>\n"
  57. "<direction>in</direction>\n"
  58. "<relatedStateVariable>InMessage</relatedStateVariable>\n"
  59. "</argument>\n"
  60. "<argument>\n"
  61. "<name>NewOutMessage</name>\n"
  62. "<direction>out</direction>\n"
  63. "<relatedStateVariable>OutMessage</relatedStateVariable>\n"
  64. "</argument>\n"
  65. "</argumentList>\n"
  66. "</action>\n"
  67. "<action>\n"
  68. "<name>PutWLANResponse</name>\n"
  69. "<argumentList>\n"
  70. "<argument>\n"
  71. "<name>NewMessage</name>\n"
  72. "<direction>in</direction>\n"
  73. "<relatedStateVariable>Message</relatedStateVariable>\n"
  74. "</argument>\n"
  75. "<argument>\n"
  76. "<name>NewWLANEventType</name>\n"
  77. "<direction>in</direction>\n"
  78. "<relatedStateVariable>WLANEventType</relatedStateVariable>\n"
  79. "</argument>\n"
  80. "<argument>\n"
  81. "<name>NewWLANEventMAC</name>\n"
  82. "<direction>in</direction>\n"
  83. "<relatedStateVariable>WLANEventMAC</relatedStateVariable>\n"
  84. "</argument>\n"
  85. "</argumentList>\n"
  86. "</action>\n"
  87. "<action>\n"
  88. "<name>SetSelectedRegistrar</name>\n"
  89. "<argumentList>\n"
  90. "<argument>\n"
  91. "<name>NewMessage</name>\n"
  92. "<direction>in</direction>\n"
  93. "<relatedStateVariable>Message</relatedStateVariable>\n"
  94. "</argument>\n"
  95. "</argumentList>\n"
  96. "</action>\n"
  97. "</actionList>\n"
  98. "<serviceStateTable>\n"
  99. "<stateVariable sendEvents=\"no\">\n"
  100. "<name>Message</name>\n"
  101. "<dataType>bin.base64</dataType>\n"
  102. "</stateVariable>\n"
  103. "<stateVariable sendEvents=\"no\">\n"
  104. "<name>InMessage</name>\n"
  105. "<dataType>bin.base64</dataType>\n"
  106. "</stateVariable>\n"
  107. "<stateVariable sendEvents=\"no\">\n"
  108. "<name>OutMessage</name>\n"
  109. "<dataType>bin.base64</dataType>\n"
  110. "</stateVariable>\n"
  111. "<stateVariable sendEvents=\"no\">\n"
  112. "<name>DeviceInfo</name>\n"
  113. "<dataType>bin.base64</dataType>\n"
  114. "</stateVariable>\n"
  115. "<stateVariable sendEvents=\"yes\">\n"
  116. "<name>APStatus</name>\n"
  117. "<dataType>ui1</dataType>\n"
  118. "</stateVariable>\n"
  119. "<stateVariable sendEvents=\"yes\">\n"
  120. "<name>STAStatus</name>\n"
  121. "<dataType>ui1</dataType>\n"
  122. "</stateVariable>\n"
  123. "<stateVariable sendEvents=\"yes\">\n"
  124. "<name>WLANEvent</name>\n"
  125. "<dataType>bin.base64</dataType>\n"
  126. "</stateVariable>\n"
  127. "<stateVariable sendEvents=\"no\">\n"
  128. "<name>WLANEventType</name>\n"
  129. "<dataType>ui1</dataType>\n"
  130. "</stateVariable>\n"
  131. "<stateVariable sendEvents=\"no\">\n"
  132. "<name>WLANEventMAC</name>\n"
  133. "<dataType>string</dataType>\n"
  134. "</stateVariable>\n"
  135. "<stateVariable sendEvents=\"no\">\n"
  136. "<name>WLANResponse</name>\n"
  137. "<dataType>bin.base64</dataType>\n"
  138. "</stateVariable>\n"
  139. "</serviceStateTable>\n"
  140. "</scpd>\n"
  141. ;
  142. static const char *wps_device_xml_prefix =
  143. "<?xml version=\"1.0\"?>\n"
  144. "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n"
  145. "<specVersion>\n"
  146. "<major>1</major>\n"
  147. "<minor>0</minor>\n"
  148. "</specVersion>\n"
  149. "<device>\n"
  150. "<deviceType>urn:schemas-wifialliance-org:device:WFADevice:1"
  151. "</deviceType>\n";
  152. static const char *wps_device_xml_postfix =
  153. "<serviceList>\n"
  154. "<service>\n"
  155. "<serviceType>urn:schemas-wifialliance-org:service:WFAWLANConfig:1"
  156. "</serviceType>\n"
  157. "<serviceId>urn:wifialliance-org:serviceId:WFAWLANConfig1</serviceId>"
  158. "\n"
  159. "<SCPDURL>" UPNP_WPS_SCPD_XML_FILE "</SCPDURL>\n"
  160. "<controlURL>" UPNP_WPS_DEVICE_CONTROL_FILE "</controlURL>\n"
  161. "<eventSubURL>" UPNP_WPS_DEVICE_EVENT_FILE "</eventSubURL>\n"
  162. "</service>\n"
  163. "</serviceList>\n"
  164. "</device>\n"
  165. "</root>\n";
  166. /* format_wps_device_xml -- produce content of "file" wps_device.xml
  167. * (UPNP_WPS_DEVICE_XML_FILE)
  168. */
  169. static void format_wps_device_xml(struct upnp_wps_device_sm *sm,
  170. struct wpabuf *buf)
  171. {
  172. const char *s;
  173. char uuid_string[80];
  174. struct upnp_wps_device_interface *iface;
  175. iface = dl_list_first(&sm->interfaces,
  176. struct upnp_wps_device_interface, list);
  177. wpabuf_put_str(buf, wps_device_xml_prefix);
  178. /*
  179. * Add required fields with default values if not configured. Add
  180. * optional and recommended fields only if configured.
  181. */
  182. s = iface->wps->friendly_name;
  183. s = ((s && *s) ? s : "WPS Access Point");
  184. xml_add_tagged_data(buf, "friendlyName", s);
  185. s = iface->wps->dev.manufacturer;
  186. s = ((s && *s) ? s : "");
  187. xml_add_tagged_data(buf, "manufacturer", s);
  188. if (iface->wps->manufacturer_url)
  189. xml_add_tagged_data(buf, "manufacturerURL",
  190. iface->wps->manufacturer_url);
  191. if (iface->wps->model_description)
  192. xml_add_tagged_data(buf, "modelDescription",
  193. iface->wps->model_description);
  194. s = iface->wps->dev.model_name;
  195. s = ((s && *s) ? s : "");
  196. xml_add_tagged_data(buf, "modelName", s);
  197. if (iface->wps->dev.model_number)
  198. xml_add_tagged_data(buf, "modelNumber",
  199. iface->wps->dev.model_number);
  200. if (iface->wps->model_url)
  201. xml_add_tagged_data(buf, "modelURL", iface->wps->model_url);
  202. if (iface->wps->dev.serial_number)
  203. xml_add_tagged_data(buf, "serialNumber",
  204. iface->wps->dev.serial_number);
  205. uuid_bin2str(iface->wps->uuid, uuid_string, sizeof(uuid_string));
  206. s = uuid_string;
  207. /* Need "uuid:" prefix, thus we can't use xml_add_tagged_data()
  208. * easily...
  209. */
  210. wpabuf_put_str(buf, "<UDN>uuid:");
  211. xml_data_encode(buf, s, os_strlen(s));
  212. wpabuf_put_str(buf, "</UDN>\n");
  213. if (iface->wps->upc)
  214. xml_add_tagged_data(buf, "UPC", iface->wps->upc);
  215. wpabuf_put_str(buf, wps_device_xml_postfix);
  216. }
  217. static void http_put_reply_code(struct wpabuf *buf, enum http_reply_code code)
  218. {
  219. wpabuf_put_str(buf, "HTTP/1.1 ");
  220. switch (code) {
  221. case HTTP_OK:
  222. wpabuf_put_str(buf, "200 OK\r\n");
  223. break;
  224. case HTTP_BAD_REQUEST:
  225. wpabuf_put_str(buf, "400 Bad request\r\n");
  226. break;
  227. case HTTP_PRECONDITION_FAILED:
  228. wpabuf_put_str(buf, "412 Precondition failed\r\n");
  229. break;
  230. case HTTP_UNIMPLEMENTED:
  231. wpabuf_put_str(buf, "501 Unimplemented\r\n");
  232. break;
  233. case HTTP_INTERNAL_SERVER_ERROR:
  234. default:
  235. wpabuf_put_str(buf, "500 Internal server error\r\n");
  236. break;
  237. }
  238. }
  239. static void http_put_date(struct wpabuf *buf)
  240. {
  241. wpabuf_put_str(buf, "Date: ");
  242. format_date(buf);
  243. wpabuf_put_str(buf, "\r\n");
  244. }
  245. static void http_put_empty(struct wpabuf *buf, enum http_reply_code code)
  246. {
  247. http_put_reply_code(buf, code);
  248. wpabuf_put_str(buf, http_server_hdr);
  249. wpabuf_put_str(buf, http_connection_close);
  250. wpabuf_put_str(buf, "Content-Length: 0\r\n"
  251. "\r\n");
  252. }
  253. /* Given that we have received a header w/ GET, act upon it
  254. *
  255. * Format of GET (case-insensitive):
  256. *
  257. * First line must be:
  258. * GET /<file> HTTP/1.1
  259. * Since we don't do anything fancy we just ignore other lines.
  260. *
  261. * Our response (if no error) which includes only required lines is:
  262. * HTTP/1.1 200 OK
  263. * Connection: close
  264. * Content-Type: text/xml
  265. * Date: <rfc1123-date>
  266. *
  267. * Header lines must end with \r\n
  268. * Per RFC 2616, content-length: is not required but connection:close
  269. * would appear to be required (given that we will be closing it!).
  270. */
  271. static void web_connection_parse_get(struct upnp_wps_device_sm *sm,
  272. struct http_request *hreq, char *filename)
  273. {
  274. struct wpabuf *buf; /* output buffer, allocated */
  275. char *put_length_here;
  276. char *body_start;
  277. enum {
  278. GET_DEVICE_XML_FILE,
  279. GET_SCPD_XML_FILE
  280. } req;
  281. size_t extra_len = 0;
  282. int body_length;
  283. char len_buf[10];
  284. struct upnp_wps_device_interface *iface;
  285. iface = dl_list_first(&sm->interfaces,
  286. struct upnp_wps_device_interface, list);
  287. /*
  288. * It is not required that filenames be case insensitive but it is
  289. * allowed and cannot hurt here.
  290. */
  291. if (os_strcasecmp(filename, UPNP_WPS_DEVICE_XML_FILE) == 0) {
  292. wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for device XML");
  293. req = GET_DEVICE_XML_FILE;
  294. extra_len = 3000;
  295. if (iface->wps->friendly_name)
  296. extra_len += os_strlen(iface->wps->friendly_name);
  297. if (iface->wps->manufacturer_url)
  298. extra_len += os_strlen(iface->wps->manufacturer_url);
  299. if (iface->wps->model_description)
  300. extra_len += os_strlen(iface->wps->model_description);
  301. if (iface->wps->model_url)
  302. extra_len += os_strlen(iface->wps->model_url);
  303. if (iface->wps->upc)
  304. extra_len += os_strlen(iface->wps->upc);
  305. } else if (!os_strcasecmp(filename, UPNP_WPS_SCPD_XML_FILE)) {
  306. wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for SCPD XML");
  307. req = GET_SCPD_XML_FILE;
  308. extra_len = os_strlen(wps_scpd_xml);
  309. } else {
  310. /* File not found */
  311. wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET file not found: %s",
  312. filename);
  313. buf = wpabuf_alloc(200);
  314. if (buf == NULL) {
  315. http_request_deinit(hreq);
  316. return;
  317. }
  318. wpabuf_put_str(buf,
  319. "HTTP/1.1 404 Not Found\r\n"
  320. "Connection: close\r\n");
  321. http_put_date(buf);
  322. /* terminating empty line */
  323. wpabuf_put_str(buf, "\r\n");
  324. goto send_buf;
  325. }
  326. buf = wpabuf_alloc(1000 + extra_len);
  327. if (buf == NULL) {
  328. http_request_deinit(hreq);
  329. return;
  330. }
  331. wpabuf_put_str(buf,
  332. "HTTP/1.1 200 OK\r\n"
  333. "Content-Type: text/xml; charset=\"utf-8\"\r\n");
  334. wpabuf_put_str(buf, "Server: Unspecified, UPnP/1.0, Unspecified\r\n");
  335. wpabuf_put_str(buf, "Connection: close\r\n");
  336. wpabuf_put_str(buf, "Content-Length: ");
  337. /*
  338. * We will paste the length in later, leaving some extra whitespace.
  339. * HTTP code is supposed to be tolerant of extra whitespace.
  340. */
  341. put_length_here = wpabuf_put(buf, 0);
  342. wpabuf_put_str(buf, " \r\n");
  343. http_put_date(buf);
  344. /* terminating empty line */
  345. wpabuf_put_str(buf, "\r\n");
  346. body_start = wpabuf_put(buf, 0);
  347. switch (req) {
  348. case GET_DEVICE_XML_FILE:
  349. format_wps_device_xml(sm, buf);
  350. break;
  351. case GET_SCPD_XML_FILE:
  352. wpabuf_put_str(buf, wps_scpd_xml);
  353. break;
  354. }
  355. /* Now patch in the content length at the end */
  356. body_length = (char *) wpabuf_put(buf, 0) - body_start;
  357. os_snprintf(len_buf, 10, "%d", body_length);
  358. os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
  359. send_buf:
  360. http_request_send_and_deinit(hreq, buf);
  361. }
  362. static enum http_reply_code
  363. web_process_get_device_info(struct upnp_wps_device_sm *sm,
  364. struct wpabuf **reply, const char **replyname)
  365. {
  366. static const char *name = "NewDeviceInfo";
  367. struct wps_config cfg;
  368. struct upnp_wps_device_interface *iface;
  369. struct upnp_wps_peer *peer;
  370. iface = dl_list_first(&sm->interfaces,
  371. struct upnp_wps_device_interface, list);
  372. peer = &iface->peer;
  373. wpa_printf(MSG_DEBUG, "WPS UPnP: GetDeviceInfo");
  374. if (iface->ctx->ap_pin == NULL)
  375. return HTTP_INTERNAL_SERVER_ERROR;
  376. /*
  377. * Request for DeviceInfo, i.e., M1 TLVs. This is a start of WPS
  378. * registration over UPnP with the AP acting as an Enrollee. It should
  379. * be noted that this is frequently used just to get the device data,
  380. * i.e., there may not be any intent to actually complete the
  381. * registration.
  382. */
  383. if (peer->wps)
  384. wps_deinit(peer->wps);
  385. os_memset(&cfg, 0, sizeof(cfg));
  386. cfg.wps = iface->wps;
  387. cfg.pin = (u8 *) iface->ctx->ap_pin;
  388. cfg.pin_len = os_strlen(iface->ctx->ap_pin);
  389. peer->wps = wps_init(&cfg);
  390. if (peer->wps) {
  391. enum wsc_op_code op_code;
  392. *reply = wps_get_msg(peer->wps, &op_code);
  393. if (*reply == NULL) {
  394. wps_deinit(peer->wps);
  395. peer->wps = NULL;
  396. }
  397. } else
  398. *reply = NULL;
  399. if (*reply == NULL) {
  400. wpa_printf(MSG_INFO, "WPS UPnP: Failed to get DeviceInfo");
  401. return HTTP_INTERNAL_SERVER_ERROR;
  402. }
  403. *replyname = name;
  404. return HTTP_OK;
  405. }
  406. static enum http_reply_code
  407. web_process_put_message(struct upnp_wps_device_sm *sm, char *data,
  408. struct wpabuf **reply, const char **replyname)
  409. {
  410. struct wpabuf *msg;
  411. static const char *name = "NewOutMessage";
  412. enum http_reply_code ret;
  413. enum wps_process_res res;
  414. enum wsc_op_code op_code;
  415. struct upnp_wps_device_interface *iface;
  416. iface = dl_list_first(&sm->interfaces,
  417. struct upnp_wps_device_interface, list);
  418. /*
  419. * PutMessage is used by external UPnP-based Registrar to perform WPS
  420. * operation with the access point itself; as compared with
  421. * PutWLANResponse which is for proxying.
  422. */
  423. wpa_printf(MSG_DEBUG, "WPS UPnP: PutMessage");
  424. msg = xml_get_base64_item(data, "NewInMessage", &ret);
  425. if (msg == NULL)
  426. return ret;
  427. res = wps_process_msg(iface->peer.wps, WSC_UPnP, msg);
  428. if (res == WPS_FAILURE)
  429. *reply = NULL;
  430. else
  431. *reply = wps_get_msg(iface->peer.wps, &op_code);
  432. wpabuf_free(msg);
  433. if (*reply == NULL)
  434. return HTTP_INTERNAL_SERVER_ERROR;
  435. *replyname = name;
  436. return HTTP_OK;
  437. }
  438. static enum http_reply_code
  439. web_process_put_wlan_response(struct upnp_wps_device_sm *sm, char *data,
  440. struct wpabuf **reply, const char **replyname)
  441. {
  442. struct wpabuf *msg;
  443. enum http_reply_code ret;
  444. u8 macaddr[ETH_ALEN];
  445. int ev_type;
  446. int type;
  447. char *val;
  448. struct upnp_wps_device_interface *iface;
  449. int ok = 0;
  450. /*
  451. * External UPnP-based Registrar is passing us a message to be proxied
  452. * over to a Wi-Fi -based client of ours.
  453. */
  454. wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse");
  455. msg = xml_get_base64_item(data, "NewMessage", &ret);
  456. if (msg == NULL) {
  457. wpa_printf(MSG_DEBUG, "WPS UPnP: Could not extract NewMessage "
  458. "from PutWLANResponse");
  459. return ret;
  460. }
  461. val = xml_get_first_item(data, "NewWLANEventType");
  462. if (val == NULL) {
  463. wpa_printf(MSG_DEBUG, "WPS UPnP: No NewWLANEventType in "
  464. "PutWLANResponse");
  465. wpabuf_free(msg);
  466. return UPNP_ARG_VALUE_INVALID;
  467. }
  468. ev_type = atol(val);
  469. os_free(val);
  470. val = xml_get_first_item(data, "NewWLANEventMAC");
  471. if (val == NULL) {
  472. wpa_printf(MSG_DEBUG, "WPS UPnP: No NewWLANEventMAC in "
  473. "PutWLANResponse");
  474. wpabuf_free(msg);
  475. return UPNP_ARG_VALUE_INVALID;
  476. }
  477. if (hwaddr_aton(val, macaddr)) {
  478. wpa_printf(MSG_DEBUG, "WPS UPnP: Invalid NewWLANEventMAC in "
  479. "PutWLANResponse: '%s'", val);
  480. #ifdef CONFIG_WPS_STRICT
  481. {
  482. struct wps_parse_attr attr;
  483. if (wps_parse_msg(msg, &attr) < 0 || attr.version2) {
  484. wpabuf_free(msg);
  485. os_free(val);
  486. return UPNP_ARG_VALUE_INVALID;
  487. }
  488. }
  489. #endif /* CONFIG_WPS_STRICT */
  490. if (hwaddr_aton2(val, macaddr) > 0) {
  491. /*
  492. * At least some versions of Intel PROset seem to be
  493. * using dot-deliminated MAC address format here.
  494. */
  495. wpa_printf(MSG_DEBUG, "WPS UPnP: Workaround - allow "
  496. "incorrect MAC address format in "
  497. "NewWLANEventMAC: %s -> " MACSTR,
  498. val, MAC2STR(macaddr));
  499. } else {
  500. wpabuf_free(msg);
  501. os_free(val);
  502. return UPNP_ARG_VALUE_INVALID;
  503. }
  504. }
  505. os_free(val);
  506. if (ev_type == UPNP_WPS_WLANEVENT_TYPE_EAP) {
  507. struct wps_parse_attr attr;
  508. if (wps_parse_msg(msg, &attr) < 0 ||
  509. attr.msg_type == NULL)
  510. type = -1;
  511. else
  512. type = *attr.msg_type;
  513. wpa_printf(MSG_DEBUG, "WPS UPnP: Message Type %d", type);
  514. } else
  515. type = -1;
  516. dl_list_for_each(iface, &sm->interfaces,
  517. struct upnp_wps_device_interface, list) {
  518. if (iface->ctx->rx_req_put_wlan_response &&
  519. iface->ctx->rx_req_put_wlan_response(iface->priv, ev_type,
  520. macaddr, msg, type)
  521. == 0)
  522. ok = 1;
  523. }
  524. if (!ok) {
  525. wpa_printf(MSG_INFO, "WPS UPnP: Fail: sm->ctx->"
  526. "rx_req_put_wlan_response");
  527. wpabuf_free(msg);
  528. return HTTP_INTERNAL_SERVER_ERROR;
  529. }
  530. wpabuf_free(msg);
  531. *replyname = NULL;
  532. *reply = NULL;
  533. return HTTP_OK;
  534. }
  535. static int find_er_addr(struct subscription *s, struct sockaddr_in *cli)
  536. {
  537. struct subscr_addr *a;
  538. dl_list_for_each(a, &s->addr_list, struct subscr_addr, list) {
  539. if (cli->sin_addr.s_addr == a->saddr.sin_addr.s_addr)
  540. return 1;
  541. }
  542. return 0;
  543. }
  544. static struct subscription * find_er(struct upnp_wps_device_sm *sm,
  545. struct sockaddr_in *cli)
  546. {
  547. struct subscription *s;
  548. dl_list_for_each(s, &sm->subscriptions, struct subscription, list)
  549. if (find_er_addr(s, cli))
  550. return s;
  551. return NULL;
  552. }
  553. static enum http_reply_code
  554. web_process_set_selected_registrar(struct upnp_wps_device_sm *sm,
  555. struct sockaddr_in *cli, char *data,
  556. struct wpabuf **reply,
  557. const char **replyname)
  558. {
  559. struct wpabuf *msg;
  560. enum http_reply_code ret;
  561. struct subscription *s;
  562. struct upnp_wps_device_interface *iface;
  563. int err = 0;
  564. wpa_printf(MSG_DEBUG, "WPS UPnP: SetSelectedRegistrar");
  565. s = find_er(sm, cli);
  566. if (s == NULL) {
  567. wpa_printf(MSG_DEBUG, "WPS UPnP: Ignore SetSelectedRegistrar "
  568. "from unknown ER");
  569. return UPNP_ACTION_FAILED;
  570. }
  571. msg = xml_get_base64_item(data, "NewMessage", &ret);
  572. if (msg == NULL)
  573. return ret;
  574. dl_list_for_each(iface, &sm->interfaces,
  575. struct upnp_wps_device_interface, list) {
  576. if (upnp_er_set_selected_registrar(iface->wps->registrar, s,
  577. msg))
  578. err = 1;
  579. }
  580. wpabuf_free(msg);
  581. if (err)
  582. return HTTP_INTERNAL_SERVER_ERROR;
  583. *replyname = NULL;
  584. *reply = NULL;
  585. return HTTP_OK;
  586. }
  587. static const char *soap_prefix =
  588. "<?xml version=\"1.0\"?>\n"
  589. "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
  590. "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
  591. "<s:Body>\n";
  592. static const char *soap_postfix =
  593. "</s:Body>\n</s:Envelope>\n";
  594. static const char *soap_error_prefix =
  595. "<s:Fault>\n"
  596. "<faultcode>s:Client</faultcode>\n"
  597. "<faultstring>UPnPError</faultstring>\n"
  598. "<detail>\n"
  599. "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">\n";
  600. static const char *soap_error_postfix =
  601. "<errorDescription>Error</errorDescription>\n"
  602. "</UPnPError>\n"
  603. "</detail>\n"
  604. "</s:Fault>\n";
  605. static void web_connection_send_reply(struct http_request *req,
  606. enum http_reply_code ret,
  607. const char *action, int action_len,
  608. const struct wpabuf *reply,
  609. const char *replyname)
  610. {
  611. struct wpabuf *buf;
  612. char *replydata;
  613. char *put_length_here = NULL;
  614. char *body_start = NULL;
  615. if (reply) {
  616. size_t len;
  617. replydata = (char *) base64_encode(wpabuf_head(reply),
  618. wpabuf_len(reply), &len);
  619. } else
  620. replydata = NULL;
  621. /* Parameters of the response:
  622. * action(action_len) -- action we are responding to
  623. * replyname -- a name we need for the reply
  624. * replydata -- NULL or null-terminated string
  625. */
  626. buf = wpabuf_alloc(1000 + (replydata ? os_strlen(replydata) : 0U) +
  627. (action_len > 0 ? action_len * 2 : 0));
  628. if (buf == NULL) {
  629. wpa_printf(MSG_INFO, "WPS UPnP: Cannot allocate reply to "
  630. "POST");
  631. os_free(replydata);
  632. http_request_deinit(req);
  633. return;
  634. }
  635. /*
  636. * Assuming we will be successful, put in the output header first.
  637. * Note: we do not keep connections alive (and httpread does
  638. * not support it)... therefore we must have Connection: close.
  639. */
  640. if (ret == HTTP_OK) {
  641. wpabuf_put_str(buf,
  642. "HTTP/1.1 200 OK\r\n"
  643. "Content-Type: text/xml; "
  644. "charset=\"utf-8\"\r\n");
  645. } else {
  646. wpabuf_printf(buf, "HTTP/1.1 %d Error\r\n", ret);
  647. }
  648. wpabuf_put_str(buf, http_connection_close);
  649. wpabuf_put_str(buf, "Content-Length: ");
  650. /*
  651. * We will paste the length in later, leaving some extra whitespace.
  652. * HTTP code is supposed to be tolerant of extra whitespace.
  653. */
  654. put_length_here = wpabuf_put(buf, 0);
  655. wpabuf_put_str(buf, " \r\n");
  656. http_put_date(buf);
  657. /* terminating empty line */
  658. wpabuf_put_str(buf, "\r\n");
  659. body_start = wpabuf_put(buf, 0);
  660. if (ret == HTTP_OK) {
  661. wpabuf_put_str(buf, soap_prefix);
  662. wpabuf_put_str(buf, "<u:");
  663. wpabuf_put_data(buf, action, action_len);
  664. wpabuf_put_str(buf, "Response xmlns:u=\"");
  665. wpabuf_put_str(buf, urn_wfawlanconfig);
  666. wpabuf_put_str(buf, "\">\n");
  667. if (replydata && replyname) {
  668. /* TODO: might possibly need to escape part of reply
  669. * data? ...
  670. * probably not, unlikely to have ampersand(&) or left
  671. * angle bracket (<) in it...
  672. */
  673. wpabuf_printf(buf, "<%s>", replyname);
  674. wpabuf_put_str(buf, replydata);
  675. wpabuf_printf(buf, "</%s>\n", replyname);
  676. }
  677. wpabuf_put_str(buf, "</u:");
  678. wpabuf_put_data(buf, action, action_len);
  679. wpabuf_put_str(buf, "Response>\n");
  680. wpabuf_put_str(buf, soap_postfix);
  681. } else {
  682. /* Error case */
  683. wpabuf_put_str(buf, soap_prefix);
  684. wpabuf_put_str(buf, soap_error_prefix);
  685. wpabuf_printf(buf, "<errorCode>%d</errorCode>\n", ret);
  686. wpabuf_put_str(buf, soap_error_postfix);
  687. wpabuf_put_str(buf, soap_postfix);
  688. }
  689. os_free(replydata);
  690. /* Now patch in the content length at the end */
  691. if (body_start && put_length_here) {
  692. int body_length = (char *) wpabuf_put(buf, 0) - body_start;
  693. char len_buf[10];
  694. os_snprintf(len_buf, sizeof(len_buf), "%d", body_length);
  695. os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
  696. }
  697. http_request_send_and_deinit(req, buf);
  698. }
  699. static const char * web_get_action(struct http_request *req,
  700. size_t *action_len)
  701. {
  702. const char *match;
  703. int match_len;
  704. char *b;
  705. char *action;
  706. *action_len = 0;
  707. /* The SOAPAction line of the header tells us what we want to do */
  708. b = http_request_get_hdr_line(req, "SOAPAction:");
  709. if (b == NULL)
  710. return NULL;
  711. if (*b == '"')
  712. b++;
  713. else
  714. return NULL;
  715. match = urn_wfawlanconfig;
  716. match_len = os_strlen(urn_wfawlanconfig) - 1;
  717. if (os_strncasecmp(b, match, match_len))
  718. return NULL;
  719. b += match_len;
  720. /* skip over version */
  721. while (isgraph(*b) && *b != '#')
  722. b++;
  723. if (*b != '#')
  724. return NULL;
  725. b++;
  726. /* Following the sharp(#) should be the action and a double quote */
  727. action = b;
  728. while (isgraph(*b) && *b != '"')
  729. b++;
  730. if (*b != '"')
  731. return NULL;
  732. *action_len = b - action;
  733. return action;
  734. }
  735. /* Given that we have received a header w/ POST, act upon it
  736. *
  737. * Format of POST (case-insensitive):
  738. *
  739. * First line must be:
  740. * POST /<file> HTTP/1.1
  741. * Since we don't do anything fancy we just ignore other lines.
  742. *
  743. * Our response (if no error) which includes only required lines is:
  744. * HTTP/1.1 200 OK
  745. * Connection: close
  746. * Content-Type: text/xml
  747. * Date: <rfc1123-date>
  748. *
  749. * Header lines must end with \r\n
  750. * Per RFC 2616, content-length: is not required but connection:close
  751. * would appear to be required (given that we will be closing it!).
  752. */
  753. static void web_connection_parse_post(struct upnp_wps_device_sm *sm,
  754. struct sockaddr_in *cli,
  755. struct http_request *req,
  756. const char *filename)
  757. {
  758. enum http_reply_code ret;
  759. char *data = http_request_get_data(req); /* body of http msg */
  760. const char *action = NULL;
  761. size_t action_len = 0;
  762. const char *replyname = NULL; /* argument name for the reply */
  763. struct wpabuf *reply = NULL; /* data for the reply */
  764. if (os_strcasecmp(filename, UPNP_WPS_DEVICE_CONTROL_FILE)) {
  765. wpa_printf(MSG_INFO, "WPS UPnP: Invalid POST filename %s",
  766. filename);
  767. ret = HTTP_NOT_FOUND;
  768. goto bad;
  769. }
  770. ret = UPNP_INVALID_ACTION;
  771. action = web_get_action(req, &action_len);
  772. if (action == NULL)
  773. goto bad;
  774. if (!os_strncasecmp("GetDeviceInfo", action, action_len))
  775. ret = web_process_get_device_info(sm, &reply, &replyname);
  776. else if (!os_strncasecmp("PutMessage", action, action_len))
  777. ret = web_process_put_message(sm, data, &reply, &replyname);
  778. else if (!os_strncasecmp("PutWLANResponse", action, action_len))
  779. ret = web_process_put_wlan_response(sm, data, &reply,
  780. &replyname);
  781. else if (!os_strncasecmp("SetSelectedRegistrar", action, action_len))
  782. ret = web_process_set_selected_registrar(sm, cli, data, &reply,
  783. &replyname);
  784. else
  785. wpa_printf(MSG_INFO, "WPS UPnP: Unknown POST type");
  786. bad:
  787. if (ret != HTTP_OK)
  788. wpa_printf(MSG_INFO, "WPS UPnP: POST failure ret=%d", ret);
  789. web_connection_send_reply(req, ret, action, action_len, reply,
  790. replyname);
  791. wpabuf_free(reply);
  792. }
  793. /* Given that we have received a header w/ SUBSCRIBE, act upon it
  794. *
  795. * Format of SUBSCRIBE (case-insensitive):
  796. *
  797. * First line must be:
  798. * SUBSCRIBE /wps_event HTTP/1.1
  799. *
  800. * Our response (if no error) which includes only required lines is:
  801. * HTTP/1.1 200 OK
  802. * Server: xx, UPnP/1.0, xx
  803. * SID: uuid:xxxxxxxxx
  804. * Timeout: Second-<n>
  805. * Content-Length: 0
  806. * Date: xxxx
  807. *
  808. * Header lines must end with \r\n
  809. * Per RFC 2616, content-length: is not required but connection:close
  810. * would appear to be required (given that we will be closing it!).
  811. */
  812. static void web_connection_parse_subscribe(struct upnp_wps_device_sm *sm,
  813. struct http_request *req,
  814. const char *filename)
  815. {
  816. struct wpabuf *buf;
  817. char *b;
  818. char *hdr = http_request_get_hdr(req);
  819. char *h;
  820. char *match;
  821. int match_len;
  822. char *end;
  823. int len;
  824. int got_nt = 0;
  825. u8 uuid[UUID_LEN];
  826. int got_uuid = 0;
  827. char *callback_urls = NULL;
  828. struct subscription *s = NULL;
  829. enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR;
  830. buf = wpabuf_alloc(1000);
  831. if (buf == NULL) {
  832. http_request_deinit(req);
  833. return;
  834. }
  835. wpa_hexdump_ascii(MSG_DEBUG, "WPS UPnP: HTTP SUBSCRIBE",
  836. (u8 *) hdr, os_strlen(hdr));
  837. /* Parse/validate headers */
  838. h = hdr;
  839. /* First line: SUBSCRIBE /wps_event HTTP/1.1
  840. * has already been parsed.
  841. */
  842. if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) {
  843. ret = HTTP_PRECONDITION_FAILED;
  844. goto error;
  845. }
  846. wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP SUBSCRIBE for event");
  847. end = os_strchr(h, '\n');
  848. while (end) {
  849. /* Option line by option line */
  850. h = end + 1;
  851. end = os_strchr(h, '\n');
  852. if (end == NULL)
  853. break; /* no unterminated lines allowed */
  854. /* NT assures that it is our type of subscription;
  855. * not used for a renewal.
  856. **/
  857. match = "NT:";
  858. match_len = os_strlen(match);
  859. if (os_strncasecmp(h, match, match_len) == 0) {
  860. h += match_len;
  861. while (*h == ' ' || *h == '\t')
  862. h++;
  863. match = "upnp:event";
  864. match_len = os_strlen(match);
  865. if (os_strncasecmp(h, match, match_len) != 0) {
  866. ret = HTTP_BAD_REQUEST;
  867. goto error;
  868. }
  869. got_nt = 1;
  870. continue;
  871. }
  872. /* HOST should refer to us */
  873. #if 0
  874. match = "HOST:";
  875. match_len = os_strlen(match);
  876. if (os_strncasecmp(h, match, match_len) == 0) {
  877. h += match_len;
  878. while (*h == ' ' || *h == '\t')
  879. h++;
  880. .....
  881. }
  882. #endif
  883. /* CALLBACK gives one or more URLs for NOTIFYs
  884. * to be sent as a result of the subscription.
  885. * Each URL is enclosed in angle brackets.
  886. */
  887. match = "CALLBACK:";
  888. match_len = os_strlen(match);
  889. if (os_strncasecmp(h, match, match_len) == 0) {
  890. h += match_len;
  891. while (*h == ' ' || *h == '\t')
  892. h++;
  893. len = end - h;
  894. os_free(callback_urls);
  895. callback_urls = dup_binstr(h, len);
  896. if (callback_urls == NULL) {
  897. ret = HTTP_INTERNAL_SERVER_ERROR;
  898. goto error;
  899. }
  900. continue;
  901. }
  902. /* SID is only for renewal */
  903. match = "SID:";
  904. match_len = os_strlen(match);
  905. if (os_strncasecmp(h, match, match_len) == 0) {
  906. h += match_len;
  907. while (*h == ' ' || *h == '\t')
  908. h++;
  909. match = "uuid:";
  910. match_len = os_strlen(match);
  911. if (os_strncasecmp(h, match, match_len) != 0) {
  912. ret = HTTP_BAD_REQUEST;
  913. goto error;
  914. }
  915. h += match_len;
  916. while (*h == ' ' || *h == '\t')
  917. h++;
  918. if (uuid_str2bin(h, uuid)) {
  919. ret = HTTP_BAD_REQUEST;
  920. goto error;
  921. }
  922. got_uuid = 1;
  923. continue;
  924. }
  925. /* TIMEOUT is requested timeout, but apparently we can
  926. * just ignore this.
  927. */
  928. }
  929. if (got_uuid) {
  930. /* renewal */
  931. wpa_printf(MSG_DEBUG, "WPS UPnP: Subscription renewal");
  932. if (callback_urls) {
  933. ret = HTTP_BAD_REQUEST;
  934. goto error;
  935. }
  936. s = subscription_renew(sm, uuid);
  937. if (s == NULL) {
  938. char str[80];
  939. uuid_bin2str(uuid, str, sizeof(str));
  940. wpa_printf(MSG_DEBUG, "WPS UPnP: Could not find "
  941. "SID %s", str);
  942. ret = HTTP_PRECONDITION_FAILED;
  943. goto error;
  944. }
  945. } else if (callback_urls) {
  946. wpa_printf(MSG_DEBUG, "WPS UPnP: New subscription");
  947. if (!got_nt) {
  948. ret = HTTP_PRECONDITION_FAILED;
  949. goto error;
  950. }
  951. s = subscription_start(sm, callback_urls);
  952. if (s == NULL) {
  953. ret = HTTP_INTERNAL_SERVER_ERROR;
  954. goto error;
  955. }
  956. } else {
  957. ret = HTTP_PRECONDITION_FAILED;
  958. goto error;
  959. }
  960. /* success */
  961. http_put_reply_code(buf, HTTP_OK);
  962. wpabuf_put_str(buf, http_server_hdr);
  963. wpabuf_put_str(buf, http_connection_close);
  964. wpabuf_put_str(buf, "Content-Length: 0\r\n");
  965. wpabuf_put_str(buf, "SID: uuid:");
  966. /* subscription id */
  967. b = wpabuf_put(buf, 0);
  968. uuid_bin2str(s->uuid, b, 80);
  969. wpa_printf(MSG_DEBUG, "WPS UPnP: Assigned SID %s", b);
  970. wpabuf_put(buf, os_strlen(b));
  971. wpabuf_put_str(buf, "\r\n");
  972. wpabuf_printf(buf, "Timeout: Second-%d\r\n", UPNP_SUBSCRIBE_SEC);
  973. http_put_date(buf);
  974. /* And empty line to terminate header: */
  975. wpabuf_put_str(buf, "\r\n");
  976. os_free(callback_urls);
  977. http_request_send_and_deinit(req, buf);
  978. return;
  979. error:
  980. /* Per UPnP spec:
  981. * Errors
  982. * Incompatible headers
  983. * 400 Bad Request. If SID header and one of NT or CALLBACK headers
  984. * are present, the publisher must respond with HTTP error
  985. * 400 Bad Request.
  986. * Missing or invalid CALLBACK
  987. * 412 Precondition Failed. If CALLBACK header is missing or does not
  988. * contain a valid HTTP URL, the publisher must respond with HTTP
  989. * error 412 Precondition Failed.
  990. * Invalid NT
  991. * 412 Precondition Failed. If NT header does not equal upnp:event,
  992. * the publisher must respond with HTTP error 412 Precondition
  993. * Failed.
  994. * [For resubscription, use 412 if unknown uuid].
  995. * Unable to accept subscription
  996. * 5xx. If a publisher is not able to accept a subscription (such as
  997. * due to insufficient resources), it must respond with a
  998. * HTTP 500-series error code.
  999. * 599 Too many subscriptions (not a standard HTTP error)
  1000. */
  1001. wpa_printf(MSG_DEBUG, "WPS UPnP: SUBSCRIBE failed - return %d", ret);
  1002. http_put_empty(buf, ret);
  1003. http_request_send_and_deinit(req, buf);
  1004. os_free(callback_urls);
  1005. }
  1006. /* Given that we have received a header w/ UNSUBSCRIBE, act upon it
  1007. *
  1008. * Format of UNSUBSCRIBE (case-insensitive):
  1009. *
  1010. * First line must be:
  1011. * UNSUBSCRIBE /wps_event HTTP/1.1
  1012. *
  1013. * Our response (if no error) which includes only required lines is:
  1014. * HTTP/1.1 200 OK
  1015. * Content-Length: 0
  1016. *
  1017. * Header lines must end with \r\n
  1018. * Per RFC 2616, content-length: is not required but connection:close
  1019. * would appear to be required (given that we will be closing it!).
  1020. */
  1021. static void web_connection_parse_unsubscribe(struct upnp_wps_device_sm *sm,
  1022. struct http_request *req,
  1023. const char *filename)
  1024. {
  1025. struct wpabuf *buf;
  1026. char *hdr = http_request_get_hdr(req);
  1027. char *h;
  1028. char *match;
  1029. int match_len;
  1030. char *end;
  1031. u8 uuid[UUID_LEN];
  1032. int got_uuid = 0;
  1033. struct subscription *s = NULL;
  1034. enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR;
  1035. /* Parse/validate headers */
  1036. h = hdr;
  1037. /* First line: UNSUBSCRIBE /wps_event HTTP/1.1
  1038. * has already been parsed.
  1039. */
  1040. if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) {
  1041. ret = HTTP_PRECONDITION_FAILED;
  1042. goto send_msg;
  1043. }
  1044. wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP UNSUBSCRIBE for event");
  1045. end = os_strchr(h, '\n');
  1046. while (end) {
  1047. /* Option line by option line */
  1048. h = end + 1;
  1049. end = os_strchr(h, '\n');
  1050. if (end == NULL)
  1051. break; /* no unterminated lines allowed */
  1052. /* HOST should refer to us */
  1053. #if 0
  1054. match = "HOST:";
  1055. match_len = os_strlen(match);
  1056. if (os_strncasecmp(h, match, match_len) == 0) {
  1057. h += match_len;
  1058. while (*h == ' ' || *h == '\t')
  1059. h++;
  1060. .....
  1061. }
  1062. #endif
  1063. match = "SID:";
  1064. match_len = os_strlen(match);
  1065. if (os_strncasecmp(h, match, match_len) == 0) {
  1066. h += match_len;
  1067. while (*h == ' ' || *h == '\t')
  1068. h++;
  1069. match = "uuid:";
  1070. match_len = os_strlen(match);
  1071. if (os_strncasecmp(h, match, match_len) != 0) {
  1072. ret = HTTP_BAD_REQUEST;
  1073. goto send_msg;
  1074. }
  1075. h += match_len;
  1076. while (*h == ' ' || *h == '\t')
  1077. h++;
  1078. if (uuid_str2bin(h, uuid)) {
  1079. ret = HTTP_BAD_REQUEST;
  1080. goto send_msg;
  1081. }
  1082. got_uuid = 1;
  1083. continue;
  1084. }
  1085. match = "NT:";
  1086. match_len = os_strlen(match);
  1087. if (os_strncasecmp(h, match, match_len) == 0) {
  1088. ret = HTTP_BAD_REQUEST;
  1089. goto send_msg;
  1090. }
  1091. match = "CALLBACK:";
  1092. match_len = os_strlen(match);
  1093. if (os_strncasecmp(h, match, match_len) == 0) {
  1094. ret = HTTP_BAD_REQUEST;
  1095. goto send_msg;
  1096. }
  1097. }
  1098. if (got_uuid) {
  1099. s = subscription_find(sm, uuid);
  1100. if (s) {
  1101. struct subscr_addr *sa;
  1102. sa = dl_list_first(&s->addr_list, struct subscr_addr,
  1103. list);
  1104. wpa_printf(MSG_DEBUG, "WPS UPnP: Unsubscribing %p %s",
  1105. s, (sa && sa->domain_and_port) ?
  1106. sa->domain_and_port : "-null-");
  1107. dl_list_del(&s->list);
  1108. subscription_destroy(s);
  1109. } else {
  1110. wpa_printf(MSG_INFO, "WPS UPnP: Could not find matching subscription to unsubscribe");
  1111. ret = HTTP_PRECONDITION_FAILED;
  1112. goto send_msg;
  1113. }
  1114. } else {
  1115. wpa_printf(MSG_INFO, "WPS UPnP: Unsubscribe fails (not "
  1116. "found)");
  1117. ret = HTTP_PRECONDITION_FAILED;
  1118. goto send_msg;
  1119. }
  1120. ret = HTTP_OK;
  1121. send_msg:
  1122. buf = wpabuf_alloc(200);
  1123. if (buf == NULL) {
  1124. http_request_deinit(req);
  1125. return;
  1126. }
  1127. http_put_empty(buf, ret);
  1128. http_request_send_and_deinit(req, buf);
  1129. }
  1130. /* Send error in response to unknown requests */
  1131. static void web_connection_unimplemented(struct http_request *req)
  1132. {
  1133. struct wpabuf *buf;
  1134. buf = wpabuf_alloc(200);
  1135. if (buf == NULL) {
  1136. http_request_deinit(req);
  1137. return;
  1138. }
  1139. http_put_empty(buf, HTTP_UNIMPLEMENTED);
  1140. http_request_send_and_deinit(req, buf);
  1141. }
  1142. /* Called when we have gotten an apparently valid http request.
  1143. */
  1144. static void web_connection_check_data(void *ctx, struct http_request *req)
  1145. {
  1146. struct upnp_wps_device_sm *sm = ctx;
  1147. enum httpread_hdr_type htype = http_request_get_type(req);
  1148. char *filename = http_request_get_uri(req);
  1149. struct sockaddr_in *cli = http_request_get_cli_addr(req);
  1150. if (!filename) {
  1151. wpa_printf(MSG_INFO, "WPS UPnP: Could not get HTTP URI");
  1152. http_request_deinit(req);
  1153. return;
  1154. }
  1155. /* Trim leading slashes from filename */
  1156. while (*filename == '/')
  1157. filename++;
  1158. wpa_printf(MSG_DEBUG, "WPS UPnP: Got HTTP request type %d from %s:%d",
  1159. htype, inet_ntoa(cli->sin_addr), htons(cli->sin_port));
  1160. switch (htype) {
  1161. case HTTPREAD_HDR_TYPE_GET:
  1162. web_connection_parse_get(sm, req, filename);
  1163. break;
  1164. case HTTPREAD_HDR_TYPE_POST:
  1165. web_connection_parse_post(sm, cli, req, filename);
  1166. break;
  1167. case HTTPREAD_HDR_TYPE_SUBSCRIBE:
  1168. web_connection_parse_subscribe(sm, req, filename);
  1169. break;
  1170. case HTTPREAD_HDR_TYPE_UNSUBSCRIBE:
  1171. web_connection_parse_unsubscribe(sm, req, filename);
  1172. break;
  1173. /* We are not required to support M-POST; just plain
  1174. * POST is supposed to work, so we only support that.
  1175. * If for some reason we need to support M-POST, it is
  1176. * mostly the same as POST, with small differences.
  1177. */
  1178. default:
  1179. /* Send 501 for anything else */
  1180. web_connection_unimplemented(req);
  1181. break;
  1182. }
  1183. }
  1184. /*
  1185. * Listening for web connections
  1186. * We have a single TCP listening port, and hand off connections as we get
  1187. * them.
  1188. */
  1189. void web_listener_stop(struct upnp_wps_device_sm *sm)
  1190. {
  1191. http_server_deinit(sm->web_srv);
  1192. sm->web_srv = NULL;
  1193. }
  1194. int web_listener_start(struct upnp_wps_device_sm *sm)
  1195. {
  1196. struct in_addr addr;
  1197. addr.s_addr = sm->ip_addr;
  1198. sm->web_srv = http_server_init(&addr, -1, web_connection_check_data,
  1199. sm);
  1200. if (sm->web_srv == NULL) {
  1201. web_listener_stop(sm);
  1202. return -1;
  1203. }
  1204. sm->web_port = http_server_get_port(sm->web_srv);
  1205. return 0;
  1206. }