wps_upnp_web.c 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324
  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 (filename == NULL)
  292. filename = "(null)"; /* just in case */
  293. if (os_strcasecmp(filename, UPNP_WPS_DEVICE_XML_FILE) == 0) {
  294. wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for device XML");
  295. req = GET_DEVICE_XML_FILE;
  296. extra_len = 3000;
  297. if (iface->wps->friendly_name)
  298. extra_len += os_strlen(iface->wps->friendly_name);
  299. if (iface->wps->manufacturer_url)
  300. extra_len += os_strlen(iface->wps->manufacturer_url);
  301. if (iface->wps->model_description)
  302. extra_len += os_strlen(iface->wps->model_description);
  303. if (iface->wps->model_url)
  304. extra_len += os_strlen(iface->wps->model_url);
  305. if (iface->wps->upc)
  306. extra_len += os_strlen(iface->wps->upc);
  307. } else if (!os_strcasecmp(filename, UPNP_WPS_SCPD_XML_FILE)) {
  308. wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for SCPD XML");
  309. req = GET_SCPD_XML_FILE;
  310. extra_len = os_strlen(wps_scpd_xml);
  311. } else {
  312. /* File not found */
  313. wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET file not found: %s",
  314. filename);
  315. buf = wpabuf_alloc(200);
  316. if (buf == NULL) {
  317. http_request_deinit(hreq);
  318. return;
  319. }
  320. wpabuf_put_str(buf,
  321. "HTTP/1.1 404 Not Found\r\n"
  322. "Connection: close\r\n");
  323. http_put_date(buf);
  324. /* terminating empty line */
  325. wpabuf_put_str(buf, "\r\n");
  326. goto send_buf;
  327. }
  328. buf = wpabuf_alloc(1000 + extra_len);
  329. if (buf == NULL) {
  330. http_request_deinit(hreq);
  331. return;
  332. }
  333. wpabuf_put_str(buf,
  334. "HTTP/1.1 200 OK\r\n"
  335. "Content-Type: text/xml; charset=\"utf-8\"\r\n");
  336. wpabuf_put_str(buf, "Server: Unspecified, UPnP/1.0, Unspecified\r\n");
  337. wpabuf_put_str(buf, "Connection: close\r\n");
  338. wpabuf_put_str(buf, "Content-Length: ");
  339. /*
  340. * We will paste the length in later, leaving some extra whitespace.
  341. * HTTP code is supposed to be tolerant of extra whitespace.
  342. */
  343. put_length_here = wpabuf_put(buf, 0);
  344. wpabuf_put_str(buf, " \r\n");
  345. http_put_date(buf);
  346. /* terminating empty line */
  347. wpabuf_put_str(buf, "\r\n");
  348. body_start = wpabuf_put(buf, 0);
  349. switch (req) {
  350. case GET_DEVICE_XML_FILE:
  351. format_wps_device_xml(sm, buf);
  352. break;
  353. case GET_SCPD_XML_FILE:
  354. wpabuf_put_str(buf, wps_scpd_xml);
  355. break;
  356. }
  357. /* Now patch in the content length at the end */
  358. body_length = (char *) wpabuf_put(buf, 0) - body_start;
  359. os_snprintf(len_buf, 10, "%d", body_length);
  360. os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
  361. send_buf:
  362. http_request_send_and_deinit(hreq, buf);
  363. }
  364. static enum http_reply_code
  365. web_process_get_device_info(struct upnp_wps_device_sm *sm,
  366. struct wpabuf **reply, const char **replyname)
  367. {
  368. static const char *name = "NewDeviceInfo";
  369. struct wps_config cfg;
  370. struct upnp_wps_device_interface *iface;
  371. struct upnp_wps_peer *peer;
  372. iface = dl_list_first(&sm->interfaces,
  373. struct upnp_wps_device_interface, list);
  374. peer = &iface->peer;
  375. wpa_printf(MSG_DEBUG, "WPS UPnP: GetDeviceInfo");
  376. if (iface->ctx->ap_pin == NULL)
  377. return HTTP_INTERNAL_SERVER_ERROR;
  378. /*
  379. * Request for DeviceInfo, i.e., M1 TLVs. This is a start of WPS
  380. * registration over UPnP with the AP acting as an Enrollee. It should
  381. * be noted that this is frequently used just to get the device data,
  382. * i.e., there may not be any intent to actually complete the
  383. * registration.
  384. */
  385. if (peer->wps)
  386. wps_deinit(peer->wps);
  387. os_memset(&cfg, 0, sizeof(cfg));
  388. cfg.wps = iface->wps;
  389. cfg.pin = (u8 *) iface->ctx->ap_pin;
  390. cfg.pin_len = os_strlen(iface->ctx->ap_pin);
  391. peer->wps = wps_init(&cfg);
  392. if (peer->wps) {
  393. enum wsc_op_code op_code;
  394. *reply = wps_get_msg(peer->wps, &op_code);
  395. if (*reply == NULL) {
  396. wps_deinit(peer->wps);
  397. peer->wps = NULL;
  398. }
  399. } else
  400. *reply = NULL;
  401. if (*reply == NULL) {
  402. wpa_printf(MSG_INFO, "WPS UPnP: Failed to get DeviceInfo");
  403. return HTTP_INTERNAL_SERVER_ERROR;
  404. }
  405. *replyname = name;
  406. return HTTP_OK;
  407. }
  408. static enum http_reply_code
  409. web_process_put_message(struct upnp_wps_device_sm *sm, char *data,
  410. struct wpabuf **reply, const char **replyname)
  411. {
  412. struct wpabuf *msg;
  413. static const char *name = "NewOutMessage";
  414. enum http_reply_code ret;
  415. enum wps_process_res res;
  416. enum wsc_op_code op_code;
  417. struct upnp_wps_device_interface *iface;
  418. iface = dl_list_first(&sm->interfaces,
  419. struct upnp_wps_device_interface, list);
  420. /*
  421. * PutMessage is used by external UPnP-based Registrar to perform WPS
  422. * operation with the access point itself; as compared with
  423. * PutWLANResponse which is for proxying.
  424. */
  425. wpa_printf(MSG_DEBUG, "WPS UPnP: PutMessage");
  426. msg = xml_get_base64_item(data, "NewInMessage", &ret);
  427. if (msg == NULL)
  428. return ret;
  429. res = wps_process_msg(iface->peer.wps, WSC_UPnP, msg);
  430. if (res == WPS_FAILURE)
  431. *reply = NULL;
  432. else
  433. *reply = wps_get_msg(iface->peer.wps, &op_code);
  434. wpabuf_free(msg);
  435. if (*reply == NULL)
  436. return HTTP_INTERNAL_SERVER_ERROR;
  437. *replyname = name;
  438. return HTTP_OK;
  439. }
  440. static enum http_reply_code
  441. web_process_put_wlan_response(struct upnp_wps_device_sm *sm, char *data,
  442. struct wpabuf **reply, const char **replyname)
  443. {
  444. struct wpabuf *msg;
  445. enum http_reply_code ret;
  446. u8 macaddr[ETH_ALEN];
  447. int ev_type;
  448. int type;
  449. char *val;
  450. struct upnp_wps_device_interface *iface;
  451. int ok = 0;
  452. /*
  453. * External UPnP-based Registrar is passing us a message to be proxied
  454. * over to a Wi-Fi -based client of ours.
  455. */
  456. wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse");
  457. msg = xml_get_base64_item(data, "NewMessage", &ret);
  458. if (msg == NULL) {
  459. wpa_printf(MSG_DEBUG, "WPS UPnP: Could not extract NewMessage "
  460. "from PutWLANResponse");
  461. return ret;
  462. }
  463. val = xml_get_first_item(data, "NewWLANEventType");
  464. if (val == NULL) {
  465. wpa_printf(MSG_DEBUG, "WPS UPnP: No NewWLANEventType in "
  466. "PutWLANResponse");
  467. wpabuf_free(msg);
  468. return UPNP_ARG_VALUE_INVALID;
  469. }
  470. ev_type = atol(val);
  471. os_free(val);
  472. val = xml_get_first_item(data, "NewWLANEventMAC");
  473. if (val == NULL) {
  474. wpa_printf(MSG_DEBUG, "WPS UPnP: No NewWLANEventMAC in "
  475. "PutWLANResponse");
  476. wpabuf_free(msg);
  477. return UPNP_ARG_VALUE_INVALID;
  478. }
  479. if (hwaddr_aton(val, macaddr)) {
  480. wpa_printf(MSG_DEBUG, "WPS UPnP: Invalid NewWLANEventMAC in "
  481. "PutWLANResponse: '%s'", val);
  482. #ifdef CONFIG_WPS_STRICT
  483. {
  484. struct wps_parse_attr attr;
  485. if (wps_parse_msg(msg, &attr) < 0 || attr.version2) {
  486. wpabuf_free(msg);
  487. os_free(val);
  488. return UPNP_ARG_VALUE_INVALID;
  489. }
  490. }
  491. #endif /* CONFIG_WPS_STRICT */
  492. if (hwaddr_aton2(val, macaddr) > 0) {
  493. /*
  494. * At least some versions of Intel PROset seem to be
  495. * using dot-deliminated MAC address format here.
  496. */
  497. wpa_printf(MSG_DEBUG, "WPS UPnP: Workaround - allow "
  498. "incorrect MAC address format in "
  499. "NewWLANEventMAC: %s -> " MACSTR,
  500. val, MAC2STR(macaddr));
  501. } else {
  502. wpabuf_free(msg);
  503. os_free(val);
  504. return UPNP_ARG_VALUE_INVALID;
  505. }
  506. }
  507. os_free(val);
  508. if (ev_type == UPNP_WPS_WLANEVENT_TYPE_EAP) {
  509. struct wps_parse_attr attr;
  510. if (wps_parse_msg(msg, &attr) < 0 ||
  511. attr.msg_type == NULL)
  512. type = -1;
  513. else
  514. type = *attr.msg_type;
  515. wpa_printf(MSG_DEBUG, "WPS UPnP: Message Type %d", type);
  516. } else
  517. type = -1;
  518. dl_list_for_each(iface, &sm->interfaces,
  519. struct upnp_wps_device_interface, list) {
  520. if (iface->ctx->rx_req_put_wlan_response &&
  521. iface->ctx->rx_req_put_wlan_response(iface->priv, ev_type,
  522. macaddr, msg, type)
  523. == 0)
  524. ok = 1;
  525. }
  526. if (!ok) {
  527. wpa_printf(MSG_INFO, "WPS UPnP: Fail: sm->ctx->"
  528. "rx_req_put_wlan_response");
  529. wpabuf_free(msg);
  530. return HTTP_INTERNAL_SERVER_ERROR;
  531. }
  532. wpabuf_free(msg);
  533. *replyname = NULL;
  534. *reply = NULL;
  535. return HTTP_OK;
  536. }
  537. static int find_er_addr(struct subscription *s, struct sockaddr_in *cli)
  538. {
  539. struct subscr_addr *a;
  540. dl_list_for_each(a, &s->addr_list, struct subscr_addr, list) {
  541. if (cli->sin_addr.s_addr == a->saddr.sin_addr.s_addr)
  542. return 1;
  543. }
  544. return 0;
  545. }
  546. static struct subscription * find_er(struct upnp_wps_device_sm *sm,
  547. struct sockaddr_in *cli)
  548. {
  549. struct subscription *s;
  550. dl_list_for_each(s, &sm->subscriptions, struct subscription, list)
  551. if (find_er_addr(s, cli))
  552. return s;
  553. return NULL;
  554. }
  555. static enum http_reply_code
  556. web_process_set_selected_registrar(struct upnp_wps_device_sm *sm,
  557. struct sockaddr_in *cli, char *data,
  558. struct wpabuf **reply,
  559. const char **replyname)
  560. {
  561. struct wpabuf *msg;
  562. enum http_reply_code ret;
  563. struct subscription *s;
  564. struct upnp_wps_device_interface *iface;
  565. int err = 0;
  566. wpa_printf(MSG_DEBUG, "WPS UPnP: SetSelectedRegistrar");
  567. s = find_er(sm, cli);
  568. if (s == NULL) {
  569. wpa_printf(MSG_DEBUG, "WPS UPnP: Ignore SetSelectedRegistrar "
  570. "from unknown ER");
  571. return UPNP_ACTION_FAILED;
  572. }
  573. msg = xml_get_base64_item(data, "NewMessage", &ret);
  574. if (msg == NULL)
  575. return ret;
  576. dl_list_for_each(iface, &sm->interfaces,
  577. struct upnp_wps_device_interface, list) {
  578. if (upnp_er_set_selected_registrar(iface->wps->registrar, s,
  579. msg))
  580. err = 1;
  581. }
  582. wpabuf_free(msg);
  583. if (err)
  584. return HTTP_INTERNAL_SERVER_ERROR;
  585. *replyname = NULL;
  586. *reply = NULL;
  587. return HTTP_OK;
  588. }
  589. static const char *soap_prefix =
  590. "<?xml version=\"1.0\"?>\n"
  591. "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
  592. "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
  593. "<s:Body>\n";
  594. static const char *soap_postfix =
  595. "</s:Body>\n</s:Envelope>\n";
  596. static const char *soap_error_prefix =
  597. "<s:Fault>\n"
  598. "<faultcode>s:Client</faultcode>\n"
  599. "<faultstring>UPnPError</faultstring>\n"
  600. "<detail>\n"
  601. "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">\n";
  602. static const char *soap_error_postfix =
  603. "<errorDescription>Error</errorDescription>\n"
  604. "</UPnPError>\n"
  605. "</detail>\n"
  606. "</s:Fault>\n";
  607. static void web_connection_send_reply(struct http_request *req,
  608. enum http_reply_code ret,
  609. const char *action, int action_len,
  610. const struct wpabuf *reply,
  611. const char *replyname)
  612. {
  613. struct wpabuf *buf;
  614. char *replydata;
  615. char *put_length_here = NULL;
  616. char *body_start = NULL;
  617. if (reply) {
  618. size_t len;
  619. replydata = (char *) base64_encode(wpabuf_head(reply),
  620. wpabuf_len(reply), &len);
  621. } else
  622. replydata = NULL;
  623. /* Parameters of the response:
  624. * action(action_len) -- action we are responding to
  625. * replyname -- a name we need for the reply
  626. * replydata -- NULL or null-terminated string
  627. */
  628. buf = wpabuf_alloc(1000 + (replydata ? os_strlen(replydata) : 0U) +
  629. (action_len > 0 ? action_len * 2 : 0));
  630. if (buf == NULL) {
  631. wpa_printf(MSG_INFO, "WPS UPnP: Cannot allocate reply to "
  632. "POST");
  633. os_free(replydata);
  634. http_request_deinit(req);
  635. return;
  636. }
  637. /*
  638. * Assuming we will be successful, put in the output header first.
  639. * Note: we do not keep connections alive (and httpread does
  640. * not support it)... therefore we must have Connection: close.
  641. */
  642. if (ret == HTTP_OK) {
  643. wpabuf_put_str(buf,
  644. "HTTP/1.1 200 OK\r\n"
  645. "Content-Type: text/xml; "
  646. "charset=\"utf-8\"\r\n");
  647. } else {
  648. wpabuf_printf(buf, "HTTP/1.1 %d Error\r\n", ret);
  649. }
  650. wpabuf_put_str(buf, http_connection_close);
  651. wpabuf_put_str(buf, "Content-Length: ");
  652. /*
  653. * We will paste the length in later, leaving some extra whitespace.
  654. * HTTP code is supposed to be tolerant of extra whitespace.
  655. */
  656. put_length_here = wpabuf_put(buf, 0);
  657. wpabuf_put_str(buf, " \r\n");
  658. http_put_date(buf);
  659. /* terminating empty line */
  660. wpabuf_put_str(buf, "\r\n");
  661. body_start = wpabuf_put(buf, 0);
  662. if (ret == HTTP_OK) {
  663. wpabuf_put_str(buf, soap_prefix);
  664. wpabuf_put_str(buf, "<u:");
  665. wpabuf_put_data(buf, action, action_len);
  666. wpabuf_put_str(buf, "Response xmlns:u=\"");
  667. wpabuf_put_str(buf, urn_wfawlanconfig);
  668. wpabuf_put_str(buf, "\">\n");
  669. if (replydata && replyname) {
  670. /* TODO: might possibly need to escape part of reply
  671. * data? ...
  672. * probably not, unlikely to have ampersand(&) or left
  673. * angle bracket (<) in it...
  674. */
  675. wpabuf_printf(buf, "<%s>", replyname);
  676. wpabuf_put_str(buf, replydata);
  677. wpabuf_printf(buf, "</%s>\n", replyname);
  678. }
  679. wpabuf_put_str(buf, "</u:");
  680. wpabuf_put_data(buf, action, action_len);
  681. wpabuf_put_str(buf, "Response>\n");
  682. wpabuf_put_str(buf, soap_postfix);
  683. } else {
  684. /* Error case */
  685. wpabuf_put_str(buf, soap_prefix);
  686. wpabuf_put_str(buf, soap_error_prefix);
  687. wpabuf_printf(buf, "<errorCode>%d</errorCode>\n", ret);
  688. wpabuf_put_str(buf, soap_error_postfix);
  689. wpabuf_put_str(buf, soap_postfix);
  690. }
  691. os_free(replydata);
  692. /* Now patch in the content length at the end */
  693. if (body_start && put_length_here) {
  694. int body_length = (char *) wpabuf_put(buf, 0) - body_start;
  695. char len_buf[10];
  696. os_snprintf(len_buf, sizeof(len_buf), "%d", body_length);
  697. os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
  698. }
  699. http_request_send_and_deinit(req, buf);
  700. }
  701. static const char * web_get_action(struct http_request *req,
  702. size_t *action_len)
  703. {
  704. const char *match;
  705. int match_len;
  706. char *b;
  707. char *action;
  708. *action_len = 0;
  709. /* The SOAPAction line of the header tells us what we want to do */
  710. b = http_request_get_hdr_line(req, "SOAPAction:");
  711. if (b == NULL)
  712. return NULL;
  713. if (*b == '"')
  714. b++;
  715. else
  716. return NULL;
  717. match = urn_wfawlanconfig;
  718. match_len = os_strlen(urn_wfawlanconfig) - 1;
  719. if (os_strncasecmp(b, match, match_len))
  720. return NULL;
  721. b += match_len;
  722. /* skip over version */
  723. while (isgraph(*b) && *b != '#')
  724. b++;
  725. if (*b != '#')
  726. return NULL;
  727. b++;
  728. /* Following the sharp(#) should be the action and a double quote */
  729. action = b;
  730. while (isgraph(*b) && *b != '"')
  731. b++;
  732. if (*b != '"')
  733. return NULL;
  734. *action_len = b - action;
  735. return action;
  736. }
  737. /* Given that we have received a header w/ POST, act upon it
  738. *
  739. * Format of POST (case-insensitive):
  740. *
  741. * First line must be:
  742. * POST /<file> HTTP/1.1
  743. * Since we don't do anything fancy we just ignore other lines.
  744. *
  745. * Our response (if no error) which includes only required lines is:
  746. * HTTP/1.1 200 OK
  747. * Connection: close
  748. * Content-Type: text/xml
  749. * Date: <rfc1123-date>
  750. *
  751. * Header lines must end with \r\n
  752. * Per RFC 2616, content-length: is not required but connection:close
  753. * would appear to be required (given that we will be closing it!).
  754. */
  755. static void web_connection_parse_post(struct upnp_wps_device_sm *sm,
  756. struct sockaddr_in *cli,
  757. struct http_request *req,
  758. const char *filename)
  759. {
  760. enum http_reply_code ret;
  761. char *data = http_request_get_data(req); /* body of http msg */
  762. const char *action = NULL;
  763. size_t action_len = 0;
  764. const char *replyname = NULL; /* argument name for the reply */
  765. struct wpabuf *reply = NULL; /* data for the reply */
  766. if (os_strcasecmp(filename, UPNP_WPS_DEVICE_CONTROL_FILE)) {
  767. wpa_printf(MSG_INFO, "WPS UPnP: Invalid POST filename %s",
  768. filename);
  769. ret = HTTP_NOT_FOUND;
  770. goto bad;
  771. }
  772. ret = UPNP_INVALID_ACTION;
  773. action = web_get_action(req, &action_len);
  774. if (action == NULL)
  775. goto bad;
  776. if (!os_strncasecmp("GetDeviceInfo", action, action_len))
  777. ret = web_process_get_device_info(sm, &reply, &replyname);
  778. else if (!os_strncasecmp("PutMessage", action, action_len))
  779. ret = web_process_put_message(sm, data, &reply, &replyname);
  780. else if (!os_strncasecmp("PutWLANResponse", action, action_len))
  781. ret = web_process_put_wlan_response(sm, data, &reply,
  782. &replyname);
  783. else if (!os_strncasecmp("SetSelectedRegistrar", action, action_len))
  784. ret = web_process_set_selected_registrar(sm, cli, data, &reply,
  785. &replyname);
  786. else
  787. wpa_printf(MSG_INFO, "WPS UPnP: Unknown POST type");
  788. bad:
  789. if (ret != HTTP_OK)
  790. wpa_printf(MSG_INFO, "WPS UPnP: POST failure ret=%d", ret);
  791. web_connection_send_reply(req, ret, action, action_len, reply,
  792. replyname);
  793. wpabuf_free(reply);
  794. }
  795. /* Given that we have received a header w/ SUBSCRIBE, act upon it
  796. *
  797. * Format of SUBSCRIBE (case-insensitive):
  798. *
  799. * First line must be:
  800. * SUBSCRIBE /wps_event HTTP/1.1
  801. *
  802. * Our response (if no error) which includes only required lines is:
  803. * HTTP/1.1 200 OK
  804. * Server: xx, UPnP/1.0, xx
  805. * SID: uuid:xxxxxxxxx
  806. * Timeout: Second-<n>
  807. * Content-Length: 0
  808. * Date: xxxx
  809. *
  810. * Header lines must end with \r\n
  811. * Per RFC 2616, content-length: is not required but connection:close
  812. * would appear to be required (given that we will be closing it!).
  813. */
  814. static void web_connection_parse_subscribe(struct upnp_wps_device_sm *sm,
  815. struct http_request *req,
  816. const char *filename)
  817. {
  818. struct wpabuf *buf;
  819. char *b;
  820. char *hdr = http_request_get_hdr(req);
  821. char *h;
  822. char *match;
  823. int match_len;
  824. char *end;
  825. int len;
  826. int got_nt = 0;
  827. u8 uuid[UUID_LEN];
  828. int got_uuid = 0;
  829. char *callback_urls = NULL;
  830. struct subscription *s = NULL;
  831. enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR;
  832. buf = wpabuf_alloc(1000);
  833. if (buf == NULL) {
  834. http_request_deinit(req);
  835. return;
  836. }
  837. wpa_hexdump_ascii(MSG_DEBUG, "WPS UPnP: HTTP SUBSCRIBE",
  838. (u8 *) hdr, os_strlen(hdr));
  839. /* Parse/validate headers */
  840. h = hdr;
  841. /* First line: SUBSCRIBE /wps_event HTTP/1.1
  842. * has already been parsed.
  843. */
  844. if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) {
  845. ret = HTTP_PRECONDITION_FAILED;
  846. goto error;
  847. }
  848. wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP SUBSCRIBE for event");
  849. end = os_strchr(h, '\n');
  850. for (; end != NULL; h = end + 1) {
  851. /* Option line by option line */
  852. h = end + 1;
  853. end = os_strchr(h, '\n');
  854. if (end == NULL)
  855. break; /* no unterminated lines allowed */
  856. /* NT assures that it is our type of subscription;
  857. * not used for a renewal.
  858. **/
  859. match = "NT:";
  860. match_len = os_strlen(match);
  861. if (os_strncasecmp(h, match, match_len) == 0) {
  862. h += match_len;
  863. while (*h == ' ' || *h == '\t')
  864. h++;
  865. match = "upnp:event";
  866. match_len = os_strlen(match);
  867. if (os_strncasecmp(h, match, match_len) != 0) {
  868. ret = HTTP_BAD_REQUEST;
  869. goto error;
  870. }
  871. got_nt = 1;
  872. continue;
  873. }
  874. /* HOST should refer to us */
  875. #if 0
  876. match = "HOST:";
  877. match_len = os_strlen(match);
  878. if (os_strncasecmp(h, match, match_len) == 0) {
  879. h += match_len;
  880. while (*h == ' ' || *h == '\t')
  881. h++;
  882. .....
  883. }
  884. #endif
  885. /* CALLBACK gives one or more URLs for NOTIFYs
  886. * to be sent as a result of the subscription.
  887. * Each URL is enclosed in angle brackets.
  888. */
  889. match = "CALLBACK:";
  890. match_len = os_strlen(match);
  891. if (os_strncasecmp(h, match, match_len) == 0) {
  892. h += match_len;
  893. while (*h == ' ' || *h == '\t')
  894. h++;
  895. len = end - h;
  896. os_free(callback_urls);
  897. callback_urls = os_malloc(len + 1);
  898. if (callback_urls == NULL) {
  899. ret = HTTP_INTERNAL_SERVER_ERROR;
  900. goto error;
  901. }
  902. os_memcpy(callback_urls, h, len);
  903. callback_urls[len] = 0;
  904. continue;
  905. }
  906. /* SID is only for renewal */
  907. match = "SID:";
  908. match_len = os_strlen(match);
  909. if (os_strncasecmp(h, match, match_len) == 0) {
  910. h += match_len;
  911. while (*h == ' ' || *h == '\t')
  912. h++;
  913. match = "uuid:";
  914. match_len = os_strlen(match);
  915. if (os_strncasecmp(h, match, match_len) != 0) {
  916. ret = HTTP_BAD_REQUEST;
  917. goto error;
  918. }
  919. h += match_len;
  920. while (*h == ' ' || *h == '\t')
  921. h++;
  922. if (uuid_str2bin(h, uuid)) {
  923. ret = HTTP_BAD_REQUEST;
  924. goto error;
  925. }
  926. got_uuid = 1;
  927. continue;
  928. }
  929. /* TIMEOUT is requested timeout, but apparently we can
  930. * just ignore this.
  931. */
  932. }
  933. if (got_uuid) {
  934. /* renewal */
  935. wpa_printf(MSG_DEBUG, "WPS UPnP: Subscription renewal");
  936. if (callback_urls) {
  937. ret = HTTP_BAD_REQUEST;
  938. goto error;
  939. }
  940. s = subscription_renew(sm, uuid);
  941. if (s == NULL) {
  942. char str[80];
  943. uuid_bin2str(uuid, str, sizeof(str));
  944. wpa_printf(MSG_DEBUG, "WPS UPnP: Could not find "
  945. "SID %s", str);
  946. ret = HTTP_PRECONDITION_FAILED;
  947. goto error;
  948. }
  949. } else if (callback_urls) {
  950. wpa_printf(MSG_DEBUG, "WPS UPnP: New subscription");
  951. if (!got_nt) {
  952. ret = HTTP_PRECONDITION_FAILED;
  953. goto error;
  954. }
  955. s = subscription_start(sm, callback_urls);
  956. if (s == NULL) {
  957. ret = HTTP_INTERNAL_SERVER_ERROR;
  958. goto error;
  959. }
  960. } else {
  961. ret = HTTP_PRECONDITION_FAILED;
  962. goto error;
  963. }
  964. /* success */
  965. http_put_reply_code(buf, HTTP_OK);
  966. wpabuf_put_str(buf, http_server_hdr);
  967. wpabuf_put_str(buf, http_connection_close);
  968. wpabuf_put_str(buf, "Content-Length: 0\r\n");
  969. wpabuf_put_str(buf, "SID: uuid:");
  970. /* subscription id */
  971. b = wpabuf_put(buf, 0);
  972. uuid_bin2str(s->uuid, b, 80);
  973. wpa_printf(MSG_DEBUG, "WPS UPnP: Assigned SID %s", b);
  974. wpabuf_put(buf, os_strlen(b));
  975. wpabuf_put_str(buf, "\r\n");
  976. wpabuf_printf(buf, "Timeout: Second-%d\r\n", UPNP_SUBSCRIBE_SEC);
  977. http_put_date(buf);
  978. /* And empty line to terminate header: */
  979. wpabuf_put_str(buf, "\r\n");
  980. os_free(callback_urls);
  981. http_request_send_and_deinit(req, buf);
  982. return;
  983. error:
  984. /* Per UPnP spec:
  985. * Errors
  986. * Incompatible headers
  987. * 400 Bad Request. If SID header and one of NT or CALLBACK headers
  988. * are present, the publisher must respond with HTTP error
  989. * 400 Bad Request.
  990. * Missing or invalid CALLBACK
  991. * 412 Precondition Failed. If CALLBACK header is missing or does not
  992. * contain a valid HTTP URL, the publisher must respond with HTTP
  993. * error 412 Precondition Failed.
  994. * Invalid NT
  995. * 412 Precondition Failed. If NT header does not equal upnp:event,
  996. * the publisher must respond with HTTP error 412 Precondition
  997. * Failed.
  998. * [For resubscription, use 412 if unknown uuid].
  999. * Unable to accept subscription
  1000. * 5xx. If a publisher is not able to accept a subscription (such as
  1001. * due to insufficient resources), it must respond with a
  1002. * HTTP 500-series error code.
  1003. * 599 Too many subscriptions (not a standard HTTP error)
  1004. */
  1005. wpa_printf(MSG_DEBUG, "WPS UPnP: SUBSCRIBE failed - return %d", ret);
  1006. http_put_empty(buf, ret);
  1007. http_request_send_and_deinit(req, buf);
  1008. os_free(callback_urls);
  1009. }
  1010. /* Given that we have received a header w/ UNSUBSCRIBE, act upon it
  1011. *
  1012. * Format of UNSUBSCRIBE (case-insensitive):
  1013. *
  1014. * First line must be:
  1015. * UNSUBSCRIBE /wps_event HTTP/1.1
  1016. *
  1017. * Our response (if no error) which includes only required lines is:
  1018. * HTTP/1.1 200 OK
  1019. * Content-Length: 0
  1020. *
  1021. * Header lines must end with \r\n
  1022. * Per RFC 2616, content-length: is not required but connection:close
  1023. * would appear to be required (given that we will be closing it!).
  1024. */
  1025. static void web_connection_parse_unsubscribe(struct upnp_wps_device_sm *sm,
  1026. struct http_request *req,
  1027. const char *filename)
  1028. {
  1029. struct wpabuf *buf;
  1030. char *hdr = http_request_get_hdr(req);
  1031. char *h;
  1032. char *match;
  1033. int match_len;
  1034. char *end;
  1035. u8 uuid[UUID_LEN];
  1036. int got_uuid = 0;
  1037. struct subscription *s = NULL;
  1038. enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR;
  1039. /* Parse/validate headers */
  1040. h = hdr;
  1041. /* First line: UNSUBSCRIBE /wps_event HTTP/1.1
  1042. * has already been parsed.
  1043. */
  1044. if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) {
  1045. ret = HTTP_PRECONDITION_FAILED;
  1046. goto send_msg;
  1047. }
  1048. wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP UNSUBSCRIBE for event");
  1049. end = os_strchr(h, '\n');
  1050. for (; end != NULL; h = end + 1) {
  1051. /* Option line by option line */
  1052. h = end + 1;
  1053. end = os_strchr(h, '\n');
  1054. if (end == NULL)
  1055. break; /* no unterminated lines allowed */
  1056. /* HOST should refer to us */
  1057. #if 0
  1058. match = "HOST:";
  1059. match_len = os_strlen(match);
  1060. if (os_strncasecmp(h, match, match_len) == 0) {
  1061. h += match_len;
  1062. while (*h == ' ' || *h == '\t')
  1063. h++;
  1064. .....
  1065. }
  1066. #endif
  1067. /* SID is only for renewal */
  1068. match = "SID:";
  1069. match_len = os_strlen(match);
  1070. if (os_strncasecmp(h, match, match_len) == 0) {
  1071. h += match_len;
  1072. while (*h == ' ' || *h == '\t')
  1073. h++;
  1074. match = "uuid:";
  1075. match_len = os_strlen(match);
  1076. if (os_strncasecmp(h, match, match_len) != 0) {
  1077. ret = HTTP_BAD_REQUEST;
  1078. goto send_msg;
  1079. }
  1080. h += match_len;
  1081. while (*h == ' ' || *h == '\t')
  1082. h++;
  1083. if (uuid_str2bin(h, uuid)) {
  1084. ret = HTTP_BAD_REQUEST;
  1085. goto send_msg;
  1086. }
  1087. got_uuid = 1;
  1088. continue;
  1089. }
  1090. }
  1091. if (got_uuid) {
  1092. s = subscription_find(sm, uuid);
  1093. if (s) {
  1094. struct subscr_addr *sa;
  1095. sa = dl_list_first(&s->addr_list, struct subscr_addr,
  1096. list);
  1097. wpa_printf(MSG_DEBUG, "WPS UPnP: Unsubscribing %p %s",
  1098. s, (sa && sa->domain_and_port) ?
  1099. sa->domain_and_port : "-null-");
  1100. dl_list_del(&s->list);
  1101. subscription_destroy(s);
  1102. }
  1103. } else {
  1104. wpa_printf(MSG_INFO, "WPS UPnP: Unsubscribe fails (not "
  1105. "found)");
  1106. ret = HTTP_PRECONDITION_FAILED;
  1107. goto send_msg;
  1108. }
  1109. ret = HTTP_OK;
  1110. send_msg:
  1111. buf = wpabuf_alloc(200);
  1112. if (buf == NULL) {
  1113. http_request_deinit(req);
  1114. return;
  1115. }
  1116. http_put_empty(buf, ret);
  1117. http_request_send_and_deinit(req, buf);
  1118. }
  1119. /* Send error in response to unknown requests */
  1120. static void web_connection_unimplemented(struct http_request *req)
  1121. {
  1122. struct wpabuf *buf;
  1123. buf = wpabuf_alloc(200);
  1124. if (buf == NULL) {
  1125. http_request_deinit(req);
  1126. return;
  1127. }
  1128. http_put_empty(buf, HTTP_UNIMPLEMENTED);
  1129. http_request_send_and_deinit(req, buf);
  1130. }
  1131. /* Called when we have gotten an apparently valid http request.
  1132. */
  1133. static void web_connection_check_data(void *ctx, struct http_request *req)
  1134. {
  1135. struct upnp_wps_device_sm *sm = ctx;
  1136. enum httpread_hdr_type htype = http_request_get_type(req);
  1137. char *filename = http_request_get_uri(req);
  1138. struct sockaddr_in *cli = http_request_get_cli_addr(req);
  1139. if (!filename) {
  1140. wpa_printf(MSG_INFO, "WPS UPnP: Could not get HTTP URI");
  1141. http_request_deinit(req);
  1142. return;
  1143. }
  1144. /* Trim leading slashes from filename */
  1145. while (*filename == '/')
  1146. filename++;
  1147. wpa_printf(MSG_DEBUG, "WPS UPnP: Got HTTP request type %d from %s:%d",
  1148. htype, inet_ntoa(cli->sin_addr), htons(cli->sin_port));
  1149. switch (htype) {
  1150. case HTTPREAD_HDR_TYPE_GET:
  1151. web_connection_parse_get(sm, req, filename);
  1152. break;
  1153. case HTTPREAD_HDR_TYPE_POST:
  1154. web_connection_parse_post(sm, cli, req, filename);
  1155. break;
  1156. case HTTPREAD_HDR_TYPE_SUBSCRIBE:
  1157. web_connection_parse_subscribe(sm, req, filename);
  1158. break;
  1159. case HTTPREAD_HDR_TYPE_UNSUBSCRIBE:
  1160. web_connection_parse_unsubscribe(sm, req, filename);
  1161. break;
  1162. /* We are not required to support M-POST; just plain
  1163. * POST is supposed to work, so we only support that.
  1164. * If for some reason we need to support M-POST, it is
  1165. * mostly the same as POST, with small differences.
  1166. */
  1167. default:
  1168. /* Send 501 for anything else */
  1169. web_connection_unimplemented(req);
  1170. break;
  1171. }
  1172. }
  1173. /*
  1174. * Listening for web connections
  1175. * We have a single TCP listening port, and hand off connections as we get
  1176. * them.
  1177. */
  1178. void web_listener_stop(struct upnp_wps_device_sm *sm)
  1179. {
  1180. http_server_deinit(sm->web_srv);
  1181. sm->web_srv = NULL;
  1182. }
  1183. int web_listener_start(struct upnp_wps_device_sm *sm)
  1184. {
  1185. struct in_addr addr;
  1186. addr.s_addr = sm->ip_addr;
  1187. sm->web_srv = http_server_init(&addr, -1, web_connection_check_data,
  1188. sm);
  1189. if (sm->web_srv == NULL) {
  1190. web_listener_stop(sm);
  1191. return -1;
  1192. }
  1193. sm->web_port = http_server_get_port(sm->web_srv);
  1194. return 0;
  1195. }