• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Hotspot 2.0 - OMA DM client
3  * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 
11 #include "common.h"
12 #include "wpa_helpers.h"
13 #include "xml-utils.h"
14 #include "http-utils.h"
15 #include "utils/browser.h"
16 #include "osu_client.h"
17 
18 
19 #define DM_SERVER_INITIATED_MGMT 1200
20 #define DM_CLIENT_INITIATED_MGMT 1201
21 #define DM_GENERIC_ALERT 1226
22 
23 /* OMA-TS-SyncML-RepPro-V1_2_2 - 10. Response Status Codes */
24 #define DM_RESP_OK 200
25 #define DM_RESP_AUTH_ACCEPTED 212
26 #define DM_RESP_CHUNKED_ITEM_ACCEPTED 213
27 #define DM_RESP_NOT_EXECUTED 215
28 #define DM_RESP_ATOMIC_ROLL_BACK_OK 216
29 #define DM_RESP_NOT_MODIFIED 304
30 #define DM_RESP_BAD_REQUEST 400
31 #define DM_RESP_UNAUTHORIZED 401
32 #define DM_RESP_FORBIDDEN 403
33 #define DM_RESP_NOT_FOUND 404
34 #define DM_RESP_COMMAND_NOT_ALLOWED 405
35 #define DM_RESP_OPTIONAL_FEATURE_NOT_SUPPORTED 406
36 #define DM_RESP_MISSING_CREDENTIALS 407
37 #define DM_RESP_CONFLICT 409
38 #define DM_RESP_GONE 410
39 #define DM_RESP_INCOMPLETE_COMMAND 412
40 #define DM_RESP_REQ_ENTITY_TOO_LARGE 413
41 #define DM_RESP_URI_TOO_LONG 414
42 #define DM_RESP_UNSUPPORTED_MEDIA_TYPE_OR_FORMAT 415
43 #define DM_RESP_REQ_TOO_BIG 416
44 #define DM_RESP_ALREADY_EXISTS 418
45 #define DM_RESP_DEVICE_FULL 420
46 #define DM_RESP_SIZE_MISMATCH 424
47 #define DM_RESP_PERMISSION_DENIED 425
48 #define DM_RESP_COMMAND_FAILED 500
49 #define DM_RESP_COMMAND_NOT_IMPLEMENTED 501
50 #define DM_RESP_ATOMIC_ROLL_BACK_FAILED 516
51 
52 #define DM_HS20_SUBSCRIPTION_CREATION \
53 	"org.wi-fi.hotspot2dot0.SubscriptionCreation"
54 #define DM_HS20_SUBSCRIPTION_PROVISIONING \
55 	"org.wi-fi.hotspot2dot0.SubscriptionProvisioning"
56 #define DM_HS20_SUBSCRIPTION_REMEDIATION \
57 	"org.wi-fi.hotspot2dot0.SubscriptionRemediation"
58 #define DM_HS20_POLICY_UPDATE \
59 	"org.wi-fi.hotspot2dot0.PolicyUpdate"
60 
61 #define DM_URI_PPS "./Wi-Fi/org.wi-fi/PerProviderSubscription"
62 #define DM_URI_LAUNCH_BROWSER \
63 	"./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/launchBrowserToURI"
64 
65 
66 static void add_item(struct hs20_osu_client *ctx, xml_node_t *parent,
67 		     const char *locuri, const char *data);
68 
69 
int2str(int val)70 static const char * int2str(int val)
71 {
72 	static char buf[20];
73 	snprintf(buf, sizeof(buf), "%d", val);
74 	return buf;
75 }
76 
77 
oma_dm_get_target_locuri(struct hs20_osu_client * ctx,xml_node_t * node)78 static char * oma_dm_get_target_locuri(struct hs20_osu_client *ctx,
79 				       xml_node_t *node)
80 {
81 	xml_node_t *locuri;
82 	char *uri, *ret = NULL;
83 
84 	locuri = get_node(ctx->xml, node, "Item/Target/LocURI");
85 	if (locuri == NULL)
86 		return NULL;
87 
88 	uri = xml_node_get_text(ctx->xml, locuri);
89 	if (uri)
90 		ret = os_strdup(uri);
91 	xml_node_get_text_free(ctx->xml, uri);
92 	return ret;
93 }
94 
95 
oma_dm_add_locuri(struct hs20_osu_client * ctx,xml_node_t * parent,const char * element,const char * uri)96 static void oma_dm_add_locuri(struct hs20_osu_client *ctx, xml_node_t *parent,
97 			      const char *element, const char *uri)
98 {
99 	xml_node_t *node;
100 
101 	node = xml_node_create(ctx->xml, parent, NULL, element);
102 	if (node == NULL)
103 		return;
104 	xml_node_create_text(ctx->xml, node, NULL, "LocURI", uri);
105 }
106 
107 
oma_dm_build_hdr(struct hs20_osu_client * ctx,const char * url,int msgid)108 static xml_node_t * oma_dm_build_hdr(struct hs20_osu_client *ctx,
109 				     const char *url, int msgid)
110 {
111 	xml_node_t *syncml, *synchdr;
112 	xml_namespace_t *ns;
113 
114 	syncml = xml_node_create_root(ctx->xml, "SYNCML:SYNCML1.2", NULL, &ns,
115 				      "SyncML");
116 
117 	synchdr = xml_node_create(ctx->xml, syncml, NULL, "SyncHdr");
118 	xml_node_create_text(ctx->xml, synchdr, NULL, "VerDTD", "1.2");
119 	xml_node_create_text(ctx->xml, synchdr, NULL, "VerProto", "DM/1.2");
120 	xml_node_create_text(ctx->xml, synchdr, NULL, "SessionID", "1");
121 	xml_node_create_text(ctx->xml, synchdr, NULL, "MsgID", int2str(msgid));
122 
123 	oma_dm_add_locuri(ctx, synchdr, "Target", url);
124 	oma_dm_add_locuri(ctx, synchdr, "Source", ctx->devid);
125 
126 	return syncml;
127 }
128 
129 
oma_dm_add_cmdid(struct hs20_osu_client * ctx,xml_node_t * parent,int cmdid)130 static void oma_dm_add_cmdid(struct hs20_osu_client *ctx, xml_node_t *parent,
131 			     int cmdid)
132 {
133 	xml_node_create_text(ctx->xml, parent, NULL, "CmdID", int2str(cmdid));
134 }
135 
136 
add_alert(struct hs20_osu_client * ctx,xml_node_t * parent,int cmdid,int data)137 static xml_node_t * add_alert(struct hs20_osu_client *ctx, xml_node_t *parent,
138 			      int cmdid, int data)
139 {
140 	xml_node_t *node;
141 
142 	node = xml_node_create(ctx->xml, parent, NULL, "Alert");
143 	if (node == NULL)
144 		return NULL;
145 	oma_dm_add_cmdid(ctx, node, cmdid);
146 	xml_node_create_text(ctx->xml, node, NULL, "Data", int2str(data));
147 
148 	return node;
149 }
150 
151 
add_status(struct hs20_osu_client * ctx,xml_node_t * parent,int msgref,int cmdref,int cmdid,const char * cmd,int data,const char * targetref)152 static xml_node_t * add_status(struct hs20_osu_client *ctx, xml_node_t *parent,
153 			       int msgref, int cmdref, int cmdid,
154 			       const char *cmd, int data, const char *targetref)
155 {
156 	xml_node_t *node;
157 
158 	node = xml_node_create(ctx->xml, parent, NULL, "Status");
159 	if (node == NULL)
160 		return NULL;
161 	oma_dm_add_cmdid(ctx, node, cmdid);
162 	xml_node_create_text(ctx->xml, node, NULL, "MsgRef", int2str(msgref));
163 	if (cmdref)
164 		xml_node_create_text(ctx->xml, node, NULL, "CmdRef",
165 				     int2str(cmdref));
166 	xml_node_create_text(ctx->xml, node, NULL, "Cmd", cmd);
167 	xml_node_create_text(ctx->xml, node, NULL, "Data", int2str(data));
168 	if (targetref) {
169 		xml_node_create_text(ctx->xml, node, NULL, "TargetRef",
170 				     targetref);
171 	}
172 
173 	return node;
174 }
175 
176 
add_results(struct hs20_osu_client * ctx,xml_node_t * parent,int msgref,int cmdref,int cmdid,const char * locuri,const char * data)177 static xml_node_t * add_results(struct hs20_osu_client *ctx, xml_node_t *parent,
178 				int msgref, int cmdref, int cmdid,
179 				const char *locuri, const char *data)
180 {
181 	xml_node_t *node;
182 
183 	node = xml_node_create(ctx->xml, parent, NULL, "Results");
184 	if (node == NULL)
185 		return NULL;
186 
187 	oma_dm_add_cmdid(ctx, node, cmdid);
188 	xml_node_create_text(ctx->xml, node, NULL, "MsgRef", int2str(msgref));
189 	xml_node_create_text(ctx->xml, node, NULL, "CmdRef", int2str(cmdref));
190 	add_item(ctx, node, locuri, data);
191 
192 	return node;
193 }
194 
195 
mo_str(struct hs20_osu_client * ctx,const char * urn,const char * fname)196 static char * mo_str(struct hs20_osu_client *ctx, const char *urn,
197 		     const char *fname)
198 {
199 	xml_node_t *fnode, *tnds;
200 	char *str;
201 
202 	fnode = node_from_file(ctx->xml, fname);
203 	if (!fnode)
204 		return NULL;
205 	tnds = mo_to_tnds(ctx->xml, fnode, 0, urn, "syncml:dmddf1.2");
206 	xml_node_free(ctx->xml, fnode);
207 	if (!tnds)
208 		return NULL;
209 
210 	str = xml_node_to_str(ctx->xml, tnds);
211 	xml_node_free(ctx->xml, tnds);
212 	if (str == NULL)
213 		return NULL;
214 	wpa_printf(MSG_INFO, "MgmtTree: %s", str);
215 
216 	return str;
217 }
218 
219 
add_item(struct hs20_osu_client * ctx,xml_node_t * parent,const char * locuri,const char * data)220 static void add_item(struct hs20_osu_client *ctx, xml_node_t *parent,
221 		     const char *locuri, const char *data)
222 {
223 	xml_node_t *item, *node;
224 
225 	item = xml_node_create(ctx->xml, parent, NULL, "Item");
226 	oma_dm_add_locuri(ctx, item, "Source", locuri);
227 	node = xml_node_create(ctx->xml, item, NULL, "Meta");
228 	xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Format",
229 				"Chr");
230 	xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Type",
231 				"text/plain");
232 	xml_node_create_text(ctx->xml, item, NULL, "Data", data);
233 }
234 
235 
add_replace_devinfo(struct hs20_osu_client * ctx,xml_node_t * parent,int cmdid)236 static void add_replace_devinfo(struct hs20_osu_client *ctx, xml_node_t *parent,
237 				int cmdid)
238 {
239 	xml_node_t *info, *child, *replace;
240 	const char *name;
241 	char locuri[200], *txt;
242 
243 	info = node_from_file(ctx->xml, "devinfo.xml");
244 	if (info == NULL) {
245 		wpa_printf(MSG_INFO, "Could not read devinfo.xml");
246 		return;
247 	}
248 
249 	replace = xml_node_create(ctx->xml, parent, NULL, "Replace");
250 	if (replace == NULL) {
251 		xml_node_free(ctx->xml, info);
252 		return;
253 	}
254 	oma_dm_add_cmdid(ctx, replace, cmdid);
255 
256 	xml_node_for_each_child(ctx->xml, child, info) {
257 		xml_node_for_each_check(ctx->xml, child);
258 		name = xml_node_get_localname(ctx->xml, child);
259 		os_snprintf(locuri, sizeof(locuri), "./DevInfo/%s", name);
260 		txt = xml_node_get_text(ctx->xml, child);
261 		if (txt) {
262 			add_item(ctx, replace, locuri, txt);
263 			xml_node_get_text_free(ctx->xml, txt);
264 		}
265 	}
266 
267 	xml_node_free(ctx->xml, info);
268 }
269 
270 
oma_dm_add_hs20_generic_alert(struct hs20_osu_client * ctx,xml_node_t * syncbody,int cmdid,const char * oper,const char * data)271 static void oma_dm_add_hs20_generic_alert(struct hs20_osu_client *ctx,
272 					  xml_node_t *syncbody,
273 					  int cmdid, const char *oper,
274 					  const char *data)
275 {
276 	xml_node_t *node, *item;
277 	char buf[200];
278 
279 	node = add_alert(ctx, syncbody, cmdid, DM_GENERIC_ALERT);
280 
281 	item = xml_node_create(ctx->xml, node, NULL, "Item");
282 	oma_dm_add_locuri(ctx, item, "Source", DM_URI_PPS);
283 	node = xml_node_create(ctx->xml, item, NULL, "Meta");
284 	snprintf(buf, sizeof(buf), "Reversed-Domain-Name: %s", oper);
285 	xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Type", buf);
286 	xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Format",
287 				"xml");
288 	xml_node_create_text(ctx->xml, item, NULL, "Data", data);
289 }
290 
291 
build_oma_dm_1(struct hs20_osu_client * ctx,const char * url,int msgid,const char * oper)292 static xml_node_t * build_oma_dm_1(struct hs20_osu_client *ctx,
293 				   const char *url, int msgid, const char *oper)
294 {
295 	xml_node_t *syncml, *syncbody;
296 	char *str;
297 	int cmdid = 0;
298 
299 	syncml = oma_dm_build_hdr(ctx, url, msgid);
300 	if (syncml == NULL)
301 		return NULL;
302 
303 	syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody");
304 	if (syncbody == NULL) {
305 		xml_node_free(ctx->xml, syncml);
306 		return NULL;
307 	}
308 
309 	cmdid++;
310 	add_alert(ctx, syncbody, cmdid, DM_CLIENT_INITIATED_MGMT);
311 
312 	str = mo_str(ctx, NULL, "devdetail.xml");
313 	if (str == NULL) {
314 		xml_node_free(ctx->xml, syncml);
315 		return NULL;
316 	}
317 	cmdid++;
318 	oma_dm_add_hs20_generic_alert(ctx, syncbody, cmdid, oper, str);
319 	os_free(str);
320 
321 	cmdid++;
322 	add_replace_devinfo(ctx, syncbody, cmdid);
323 
324 	xml_node_create(ctx->xml, syncbody, NULL, "Final");
325 
326 	return syncml;
327 }
328 
329 
build_oma_dm_1_sub_reg(struct hs20_osu_client * ctx,const char * url,int msgid)330 static xml_node_t * build_oma_dm_1_sub_reg(struct hs20_osu_client *ctx,
331 					   const char *url, int msgid)
332 {
333 	xml_node_t *syncml;
334 
335 	syncml = build_oma_dm_1(ctx, url, msgid, DM_HS20_SUBSCRIPTION_CREATION);
336 	if (syncml)
337 		debug_dump_node(ctx, "OMA-DM Package 1 (sub reg)", syncml);
338 
339 	return syncml;
340 }
341 
342 
build_oma_dm_1_sub_prov(struct hs20_osu_client * ctx,const char * url,int msgid)343 static xml_node_t * build_oma_dm_1_sub_prov(struct hs20_osu_client *ctx,
344 					    const char *url, int msgid)
345 {
346 	xml_node_t *syncml;
347 
348 	syncml = build_oma_dm_1(ctx, url, msgid,
349 				DM_HS20_SUBSCRIPTION_PROVISIONING);
350 	if (syncml)
351 		debug_dump_node(ctx, "OMA-DM Package 1 (sub prov)", syncml);
352 
353 	return syncml;
354 }
355 
356 
build_oma_dm_1_pol_upd(struct hs20_osu_client * ctx,const char * url,int msgid)357 static xml_node_t * build_oma_dm_1_pol_upd(struct hs20_osu_client *ctx,
358 					   const char *url, int msgid)
359 {
360 	xml_node_t *syncml;
361 
362 	syncml = build_oma_dm_1(ctx, url, msgid, DM_HS20_POLICY_UPDATE);
363 	if (syncml)
364 		debug_dump_node(ctx, "OMA-DM Package 1 (pol upd)", syncml);
365 
366 	return syncml;
367 }
368 
369 
build_oma_dm_1_sub_rem(struct hs20_osu_client * ctx,const char * url,int msgid)370 static xml_node_t * build_oma_dm_1_sub_rem(struct hs20_osu_client *ctx,
371 					   const char *url, int msgid)
372 {
373 	xml_node_t *syncml;
374 
375 	syncml = build_oma_dm_1(ctx, url, msgid,
376 				DM_HS20_SUBSCRIPTION_REMEDIATION);
377 	if (syncml)
378 		debug_dump_node(ctx, "OMA-DM Package 1 (sub rem)", syncml);
379 
380 	return syncml;
381 }
382 
383 
oma_dm_exec_browser(struct hs20_osu_client * ctx,xml_node_t * exec)384 static int oma_dm_exec_browser(struct hs20_osu_client *ctx, xml_node_t *exec)
385 {
386 	xml_node_t *node;
387 	char *data;
388 	int res;
389 
390 	node = get_node(ctx->xml, exec, "Item/Data");
391 	if (node == NULL) {
392 		wpa_printf(MSG_INFO, "No Data node found");
393 		return DM_RESP_BAD_REQUEST;
394 	}
395 
396 	data = xml_node_get_text(ctx->xml, node);
397 	wpa_printf(MSG_INFO, "Data: %s", data);
398 	wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data);
399 	write_summary(ctx, "Launch browser to URI '%s'", data);
400 	res = hs20_web_browser(data);
401 	xml_node_get_text_free(ctx->xml, data);
402 	if (res > 0) {
403 		wpa_printf(MSG_INFO, "User response in browser completed successfully");
404 		write_summary(ctx, "User response in browser completed successfully");
405 		return DM_RESP_OK;
406 	} else {
407 		wpa_printf(MSG_INFO, "Failed to receive user response");
408 		write_summary(ctx, "Failed to receive user response");
409 		return DM_RESP_COMMAND_FAILED;
410 	}
411 }
412 
413 
oma_dm_exec_get_cert(struct hs20_osu_client * ctx,xml_node_t * exec)414 static int oma_dm_exec_get_cert(struct hs20_osu_client *ctx, xml_node_t *exec)
415 {
416 	xml_node_t *node, *getcert;
417 	char *data;
418 	const char *name;
419 	int res;
420 
421 	wpa_printf(MSG_INFO, "Client certificate enrollment");
422 	write_summary(ctx, "Client certificate enrollment");
423 
424 	node = get_node(ctx->xml, exec, "Item/Data");
425 	if (node == NULL) {
426 		wpa_printf(MSG_INFO, "No Data node found");
427 		return DM_RESP_BAD_REQUEST;
428 	}
429 
430 	data = xml_node_get_text(ctx->xml, node);
431 	wpa_printf(MSG_INFO, "Data: %s", data);
432 	getcert = xml_node_from_buf(ctx->xml, data);
433 	xml_node_get_text_free(ctx->xml, data);
434 
435 	if (getcert == NULL) {
436 		wpa_printf(MSG_INFO, "Could not parse Item/Data node contents");
437 		return DM_RESP_BAD_REQUEST;
438 	}
439 
440 	debug_dump_node(ctx, "OMA-DM getCertificate", getcert);
441 
442 	name = xml_node_get_localname(ctx->xml, getcert);
443 	if (name == NULL || os_strcasecmp(name, "getCertificate") != 0) {
444 		wpa_printf(MSG_INFO, "Unexpected getCertificate node name '%s'",
445 			   name);
446 		return DM_RESP_BAD_REQUEST;
447 	}
448 
449 	res = osu_get_certificate(ctx, getcert);
450 
451 	xml_node_free(ctx->xml, getcert);
452 
453 	return res == 0 ? DM_RESP_OK : DM_RESP_COMMAND_FAILED;
454 }
455 
456 
oma_dm_exec(struct hs20_osu_client * ctx,xml_node_t * exec)457 static int oma_dm_exec(struct hs20_osu_client *ctx, xml_node_t *exec)
458 {
459 	char *locuri;
460 	int ret;
461 
462 	locuri = oma_dm_get_target_locuri(ctx, exec);
463 	if (locuri == NULL) {
464 		wpa_printf(MSG_INFO, "No Target LocURI node found");
465 		return DM_RESP_BAD_REQUEST;
466 	}
467 
468 	wpa_printf(MSG_INFO, "Target LocURI: %s", locuri);
469 
470 	if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/"
471 			  "launchBrowserToURI") == 0) {
472 		ret = oma_dm_exec_browser(ctx, exec);
473 	} else if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/"
474 			  "getCertificate") == 0) {
475 		ret = oma_dm_exec_get_cert(ctx, exec);
476 	} else {
477 		wpa_printf(MSG_INFO, "Unsupported exec Target LocURI");
478 		ret = DM_RESP_NOT_FOUND;
479 	}
480 	os_free(locuri);
481 
482 	return ret;
483 }
484 
485 
oma_dm_run_add(struct hs20_osu_client * ctx,const char * locuri,xml_node_t * add,xml_node_t * pps,const char * pps_fname)486 static int oma_dm_run_add(struct hs20_osu_client *ctx, const char *locuri,
487 			  xml_node_t *add, xml_node_t *pps,
488 			  const char *pps_fname)
489 {
490 	const char *pos;
491 	size_t fqdn_len;
492 	xml_node_t *node, *tnds, *unode, *pps_node;
493 	char *data, *uri, *upos, *end;
494 	int use_tnds = 0;
495 	size_t uri_len;
496 
497 	wpa_printf(MSG_INFO, "Add command target LocURI: %s", locuri);
498 
499 	if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
500 		wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi");
501 		return DM_RESP_PERMISSION_DENIED;
502 	}
503 	pos = locuri + 8;
504 
505 	if (ctx->fqdn == NULL)
506 		return DM_RESP_COMMAND_FAILED;
507 	fqdn_len = os_strlen(ctx->fqdn);
508 	if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
509 	    pos[fqdn_len] != '/') {
510 		wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi/%s",
511 			   ctx->fqdn);
512 		return DM_RESP_PERMISSION_DENIED;
513 	}
514 	pos += fqdn_len + 1;
515 
516 	if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
517 		wpa_printf(MSG_INFO,
518 			   "Do not allow Add outside ./Wi-Fi/%s/PerProviderSubscription",
519 			   ctx->fqdn);
520 		return DM_RESP_PERMISSION_DENIED;
521 	}
522 	pos += 24;
523 
524 	wpa_printf(MSG_INFO, "Add command for PPS node %s", pos);
525 
526 	pps_node = get_node(ctx->xml, pps, pos);
527 	if (pps_node) {
528 		wpa_printf(MSG_INFO, "Specified PPS node exists already");
529 		return DM_RESP_ALREADY_EXISTS;
530 	}
531 
532 	uri = os_strdup(pos);
533 	if (uri == NULL)
534 		return DM_RESP_COMMAND_FAILED;
535 	while (!pps_node) {
536 		upos = os_strrchr(uri, '/');
537 		if (!upos)
538 			break;
539 		upos[0] = '\0';
540 		pps_node = get_node(ctx->xml, pps, uri);
541 		wpa_printf(MSG_INFO, "Node %s %s", uri,
542 			   pps_node ? "exists" : "does not exist");
543 	}
544 
545 	wpa_printf(MSG_INFO, "Parent URI: %s", uri);
546 
547 	if (!pps_node) {
548 		/* Add at root of PPS MO */
549 		pps_node = pps;
550 	}
551 
552 	uri_len = os_strlen(uri);
553 	os_strlcpy(uri, pos + uri_len, os_strlen(pos));
554 	upos = uri;
555 	while (*upos == '/')
556 		upos++;
557 	wpa_printf(MSG_INFO, "Nodes to add: %s", upos);
558 
559 	for (;;) {
560 		end = os_strchr(upos, '/');
561 		if (!end)
562 			break;
563 		*end = '\0';
564 		wpa_printf(MSG_INFO, "Adding interim node %s", upos);
565 		pps_node = xml_node_create(ctx->xml, pps_node, NULL, upos);
566 		if (pps_node == NULL) {
567 			os_free(uri);
568 			return DM_RESP_COMMAND_FAILED;
569 		}
570 		upos = end + 1;
571 	}
572 
573 	wpa_printf(MSG_INFO, "Adding node %s", upos);
574 
575 	node = get_node(ctx->xml, add, "Item/Meta/Type");
576 	if (node) {
577 		char *type;
578 		type = xml_node_get_text(ctx->xml, node);
579 		use_tnds = node &&
580 			os_strstr(type, "application/vnd.syncml.dmtnds+xml");
581 	}
582 
583 	node = get_node(ctx->xml, add, "Item/Data");
584 	if (node == NULL) {
585 		wpa_printf(MSG_INFO, "No Add/Item/Data found");
586 		os_free(uri);
587 		return DM_RESP_BAD_REQUEST;
588 	}
589 
590 	data = xml_node_get_text(ctx->xml, node);
591 	if (data == NULL) {
592 		wpa_printf(MSG_INFO, "Could not get Add/Item/Data text");
593 		os_free(uri);
594 		return DM_RESP_BAD_REQUEST;
595 	}
596 
597 	wpa_printf(MSG_DEBUG, "Add/Item/Data: %s", data);
598 
599 	if (use_tnds) {
600 		tnds = xml_node_from_buf(ctx->xml, data);
601 		xml_node_get_text_free(ctx->xml, data);
602 		if (tnds == NULL) {
603 			wpa_printf(MSG_INFO,
604 				   "Could not parse Add/Item/Data text");
605 			os_free(uri);
606 			return DM_RESP_BAD_REQUEST;
607 		}
608 
609 		unode = tnds_to_mo(ctx->xml, tnds);
610 		xml_node_free(ctx->xml, tnds);
611 		if (unode == NULL) {
612 			wpa_printf(MSG_INFO, "Could not parse TNDS text");
613 			os_free(uri);
614 			return DM_RESP_BAD_REQUEST;
615 		}
616 
617 		debug_dump_node(ctx, "Parsed TNDS", unode);
618 
619 		xml_node_add_child(ctx->xml, pps_node, unode);
620 	} else {
621 		/* TODO: What to do here? */
622 		os_free(uri);
623 		return DM_RESP_BAD_REQUEST;
624 	}
625 
626 	os_free(uri);
627 
628 	if (update_pps_file(ctx, pps_fname, pps) < 0)
629 		return DM_RESP_COMMAND_FAILED;
630 
631 	ctx->pps_updated = 1;
632 
633 	return DM_RESP_OK;
634 }
635 
636 
oma_dm_add(struct hs20_osu_client * ctx,xml_node_t * add,xml_node_t * pps,const char * pps_fname)637 static int oma_dm_add(struct hs20_osu_client *ctx, xml_node_t *add,
638 		      xml_node_t *pps, const char *pps_fname)
639 {
640 	xml_node_t *node;
641 	char *locuri;
642 	char fname[300];
643 	int ret;
644 
645 	node = get_node(ctx->xml, add, "Item/Target/LocURI");
646 	if (node == NULL) {
647 		wpa_printf(MSG_INFO, "No Target LocURI node found");
648 		return DM_RESP_BAD_REQUEST;
649 	}
650 	locuri = xml_node_get_text(ctx->xml, node);
651 	wpa_printf(MSG_INFO, "Target LocURI: %s", locuri);
652 	if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
653 		wpa_printf(MSG_INFO, "Unsupported Add Target LocURI");
654 		xml_node_get_text_free(ctx->xml, locuri);
655 		return DM_RESP_PERMISSION_DENIED;
656 	}
657 
658 	node = get_node(ctx->xml, add, "Item/Data");
659 	if (node == NULL) {
660 		wpa_printf(MSG_INFO, "No Data node found");
661 		xml_node_get_text_free(ctx->xml, locuri);
662 		return DM_RESP_BAD_REQUEST;
663 	}
664 
665 	if (pps_fname && os_file_exists(pps_fname)) {
666 		ret = oma_dm_run_add(ctx, locuri, add, pps, pps_fname);
667 		if (ret != DM_RESP_OK) {
668 			xml_node_get_text_free(ctx->xml, locuri);
669 			return ret;
670 		}
671 		ret = 0;
672 		os_strlcpy(fname, pps_fname, sizeof(fname));
673 	} else
674 		ret = hs20_add_pps_mo(ctx, locuri, node, fname, sizeof(fname));
675 	xml_node_get_text_free(ctx->xml, locuri);
676 	if (ret < 0)
677 		return ret == -2 ? DM_RESP_ALREADY_EXISTS :
678 			DM_RESP_COMMAND_FAILED;
679 
680 	if (ctx->no_reconnect == 2) {
681 		os_snprintf(ctx->pps_fname, sizeof(ctx->pps_fname), "%s",
682 			    fname);
683 		ctx->pps_cred_set = 1;
684 		return DM_RESP_OK;
685 	}
686 
687 	wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
688 	cmd_set_pps(ctx, fname);
689 
690 	if (ctx->no_reconnect)
691 		return DM_RESP_OK;
692 
693 	wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
694 	if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
695 		wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
696 
697 	return DM_RESP_OK;
698 }
699 
700 
oma_dm_replace(struct hs20_osu_client * ctx,xml_node_t * replace,xml_node_t * pps,const char * pps_fname)701 static int oma_dm_replace(struct hs20_osu_client *ctx, xml_node_t *replace,
702 			  xml_node_t *pps, const char *pps_fname)
703 {
704 	char *locuri, *pos;
705 	size_t fqdn_len;
706 	xml_node_t *node, *tnds, *unode, *pps_node, *parent;
707 	char *data;
708 	int use_tnds = 0;
709 
710 	locuri = oma_dm_get_target_locuri(ctx, replace);
711 	if (locuri == NULL)
712 		return DM_RESP_BAD_REQUEST;
713 
714 	wpa_printf(MSG_INFO, "Replace command target LocURI: %s", locuri);
715 	if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
716 		wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi");
717 		os_free(locuri);
718 		return DM_RESP_PERMISSION_DENIED;
719 	}
720 	pos = locuri + 8;
721 
722 	if (ctx->fqdn == NULL) {
723 		os_free(locuri);
724 		return DM_RESP_COMMAND_FAILED;
725 	}
726 	fqdn_len = os_strlen(ctx->fqdn);
727 	if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
728 	    pos[fqdn_len] != '/') {
729 		wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi/%s",
730 			   ctx->fqdn);
731 		os_free(locuri);
732 		return DM_RESP_PERMISSION_DENIED;
733 	}
734 	pos += fqdn_len + 1;
735 
736 	if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
737 		wpa_printf(MSG_INFO,
738 			   "Do not allow Replace outside ./Wi-Fi/%s/PerProviderSubscription",
739 			   ctx->fqdn);
740 		os_free(locuri);
741 		return DM_RESP_PERMISSION_DENIED;
742 	}
743 	pos += 24;
744 
745 	wpa_printf(MSG_INFO, "Replace command for PPS node %s", pos);
746 
747 	pps_node = get_node(ctx->xml, pps, pos);
748 	if (pps_node == NULL) {
749 		wpa_printf(MSG_INFO, "Specified PPS node not found");
750 		os_free(locuri);
751 		return DM_RESP_NOT_FOUND;
752 	}
753 
754 	node = get_node(ctx->xml, replace, "Item/Meta/Type");
755 	if (node) {
756 		char *type;
757 		type = xml_node_get_text(ctx->xml, node);
758 		use_tnds = node &&
759 			os_strstr(type, "application/vnd.syncml.dmtnds+xml");
760 	}
761 
762 	node = get_node(ctx->xml, replace, "Item/Data");
763 	if (node == NULL) {
764 		wpa_printf(MSG_INFO, "No Replace/Item/Data found");
765 		os_free(locuri);
766 		return DM_RESP_BAD_REQUEST;
767 	}
768 
769 	data = xml_node_get_text(ctx->xml, node);
770 	if (data == NULL) {
771 		wpa_printf(MSG_INFO, "Could not get Replace/Item/Data text");
772 		os_free(locuri);
773 		return DM_RESP_BAD_REQUEST;
774 	}
775 
776 	wpa_printf(MSG_DEBUG, "Replace/Item/Data: %s", data);
777 
778 	if (use_tnds) {
779 		tnds = xml_node_from_buf(ctx->xml, data);
780 		xml_node_get_text_free(ctx->xml, data);
781 		if (tnds == NULL) {
782 			wpa_printf(MSG_INFO,
783 				   "Could not parse Replace/Item/Data text");
784 			os_free(locuri);
785 			return DM_RESP_BAD_REQUEST;
786 		}
787 
788 		unode = tnds_to_mo(ctx->xml, tnds);
789 		xml_node_free(ctx->xml, tnds);
790 		if (unode == NULL) {
791 			wpa_printf(MSG_INFO, "Could not parse TNDS text");
792 			os_free(locuri);
793 			return DM_RESP_BAD_REQUEST;
794 		}
795 
796 		debug_dump_node(ctx, "Parsed TNDS", unode);
797 
798 		parent = xml_node_get_parent(ctx->xml, pps_node);
799 		xml_node_detach(ctx->xml, pps_node);
800 		xml_node_add_child(ctx->xml, parent, unode);
801 	} else {
802 		xml_node_set_text(ctx->xml, pps_node, data);
803 		xml_node_get_text_free(ctx->xml, data);
804 	}
805 
806 	os_free(locuri);
807 
808 	if (update_pps_file(ctx, pps_fname, pps) < 0)
809 		return DM_RESP_COMMAND_FAILED;
810 
811 	ctx->pps_updated = 1;
812 
813 	return DM_RESP_OK;
814 }
815 
816 
oma_dm_get(struct hs20_osu_client * ctx,xml_node_t * get,xml_node_t * pps,const char * pps_fname,char ** value)817 static int oma_dm_get(struct hs20_osu_client *ctx, xml_node_t *get,
818 		      xml_node_t *pps, const char *pps_fname, char **value)
819 {
820 	char *locuri, *pos;
821 	size_t fqdn_len;
822 	xml_node_t *pps_node;
823 	const char *name;
824 
825 	*value = NULL;
826 
827 	locuri = oma_dm_get_target_locuri(ctx, get);
828 	if (locuri == NULL)
829 		return DM_RESP_BAD_REQUEST;
830 
831 	wpa_printf(MSG_INFO, "Get command target LocURI: %s", locuri);
832 	if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
833 		wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi");
834 		os_free(locuri);
835 		return DM_RESP_PERMISSION_DENIED;
836 	}
837 	pos = locuri + 8;
838 
839 	if (ctx->fqdn == NULL)
840 		return DM_RESP_COMMAND_FAILED;
841 	fqdn_len = os_strlen(ctx->fqdn);
842 	if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
843 	    pos[fqdn_len] != '/') {
844 		wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi/%s",
845 			   ctx->fqdn);
846 		os_free(locuri);
847 		return DM_RESP_PERMISSION_DENIED;
848 	}
849 	pos += fqdn_len + 1;
850 
851 	if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
852 		wpa_printf(MSG_INFO,
853 			   "Do not allow Get outside ./Wi-Fi/%s/PerProviderSubscription",
854 			   ctx->fqdn);
855 		os_free(locuri);
856 		return DM_RESP_PERMISSION_DENIED;
857 	}
858 	pos += 24;
859 
860 	wpa_printf(MSG_INFO, "Get command for PPS node %s", pos);
861 
862 	pps_node = get_node(ctx->xml, pps, pos);
863 	if (pps_node == NULL) {
864 		wpa_printf(MSG_INFO, "Specified PPS node not found");
865 		os_free(locuri);
866 		return DM_RESP_NOT_FOUND;
867 	}
868 
869 	name = xml_node_get_localname(ctx->xml, pps_node);
870 	wpa_printf(MSG_INFO, "Get command returned node with name '%s'", name);
871 	if (os_strcasecmp(name, "Password") == 0) {
872 		wpa_printf(MSG_INFO, "Do not allow Get for Password node");
873 		os_free(locuri);
874 		return DM_RESP_PERMISSION_DENIED;
875 	}
876 
877 	/*
878 	 * TODO: No support for DMTNDS, so if interior node, reply with a
879 	 * list of children node names in Results element. The child list type is
880 	 * defined in [DMTND].
881 	 */
882 
883 	*value = xml_node_get_text(ctx->xml, pps_node);
884 	if (*value == NULL)
885 		return DM_RESP_COMMAND_FAILED;
886 
887 	return DM_RESP_OK;
888 }
889 
890 
oma_dm_get_cmdid(struct hs20_osu_client * ctx,xml_node_t * node)891 static int oma_dm_get_cmdid(struct hs20_osu_client *ctx, xml_node_t *node)
892 {
893 	xml_node_t *cnode;
894 	char *str;
895 	int ret;
896 
897 	cnode = get_node(ctx->xml, node, "CmdID");
898 	if (cnode == NULL)
899 		return 0;
900 
901 	str = xml_node_get_text(ctx->xml, cnode);
902 	if (str == NULL)
903 		return 0;
904 	ret = atoi(str);
905 	xml_node_get_text_free(ctx->xml, str);
906 	return ret;
907 }
908 
909 
oma_dm_send_recv(struct hs20_osu_client * ctx,const char * url,xml_node_t * syncml,const char * ext_hdr,const char * username,const char * password,const char * client_cert,const char * client_key)910 static xml_node_t * oma_dm_send_recv(struct hs20_osu_client *ctx,
911 				     const char *url, xml_node_t *syncml,
912 				     const char *ext_hdr,
913 				     const char *username, const char *password,
914 				     const char *client_cert,
915 				     const char *client_key)
916 {
917 	xml_node_t *resp;
918 	char *str, *res;
919 	char *resp_uri = NULL;
920 
921 	str = xml_node_to_str(ctx->xml, syncml);
922 	xml_node_free(ctx->xml, syncml);
923 	if (str == NULL)
924 		return NULL;
925 
926 	wpa_printf(MSG_INFO, "Send OMA DM Package");
927 	write_summary(ctx, "Send OMA DM Package");
928 	os_free(ctx->server_url);
929 	ctx->server_url = os_strdup(url);
930 	res = http_post(ctx->http, url, str, "application/vnd.syncml.dm+xml",
931 			ext_hdr, ctx->ca_fname, username, password,
932 			client_cert, client_key, NULL);
933 	os_free(str);
934 	os_free(resp_uri);
935 	resp_uri = NULL;
936 
937 	if (res == NULL) {
938 		const char *err = http_get_err(ctx->http);
939 		if (err) {
940 			wpa_printf(MSG_INFO, "HTTP error: %s", err);
941 			write_result(ctx, "HTTP error: %s", err);
942 		} else {
943 			write_summary(ctx, "Failed to send OMA DM Package");
944 		}
945 		return NULL;
946 	}
947 	wpa_printf(MSG_DEBUG, "Server response: %s", res);
948 
949 	wpa_printf(MSG_INFO, "Process OMA DM Package");
950 	write_summary(ctx, "Process received OMA DM Package");
951 	resp = xml_node_from_buf(ctx->xml, res);
952 	os_free(res);
953 	if (resp == NULL) {
954 		wpa_printf(MSG_INFO, "Failed to parse OMA DM response");
955 		return NULL;
956 	}
957 
958 	debug_dump_node(ctx, "OMA DM Package", resp);
959 
960 	return resp;
961 }
962 
963 
oma_dm_process(struct hs20_osu_client * ctx,const char * url,xml_node_t * resp,int msgid,char ** ret_resp_uri,xml_node_t * pps,const char * pps_fname)964 static xml_node_t * oma_dm_process(struct hs20_osu_client *ctx, const char *url,
965 				   xml_node_t *resp, int msgid,
966 				   char **ret_resp_uri,
967 				   xml_node_t *pps, const char *pps_fname)
968 {
969 	xml_node_t *syncml, *syncbody, *hdr, *body, *child;
970 	const char *name;
971 	char *resp_uri = NULL;
972 	int server_msgid = 0;
973 	int cmdid = 0;
974 	int server_cmdid;
975 	int resp_needed = 0;
976 	char *tmp;
977 	int final = 0;
978 	char *locuri;
979 
980 	*ret_resp_uri = NULL;
981 
982 	name = xml_node_get_localname(ctx->xml, resp);
983 	if (name == NULL || os_strcasecmp(name, "SyncML") != 0) {
984 		wpa_printf(MSG_INFO, "SyncML node not found");
985 		return NULL;
986 	}
987 
988 	hdr = get_node(ctx->xml, resp, "SyncHdr");
989 	body = get_node(ctx->xml, resp, "SyncBody");
990 	if (hdr == NULL || body == NULL) {
991 		wpa_printf(MSG_INFO, "Could not find SyncHdr or SyncBody");
992 		return NULL;
993 	}
994 
995 	xml_node_for_each_child(ctx->xml, child, hdr) {
996 		xml_node_for_each_check(ctx->xml, child);
997 		name = xml_node_get_localname(ctx->xml, child);
998 		wpa_printf(MSG_INFO, "SyncHdr %s", name);
999 		if (os_strcasecmp(name, "RespURI") == 0) {
1000 			tmp = xml_node_get_text(ctx->xml, child);
1001 			if (tmp)
1002 				resp_uri = os_strdup(tmp);
1003 			xml_node_get_text_free(ctx->xml, tmp);
1004 		} else if (os_strcasecmp(name, "MsgID") == 0) {
1005 			tmp = xml_node_get_text(ctx->xml, child);
1006 			if (tmp)
1007 				server_msgid = atoi(tmp);
1008 			xml_node_get_text_free(ctx->xml, tmp);
1009 		}
1010 	}
1011 
1012 	wpa_printf(MSG_INFO, "Server MsgID: %d", server_msgid);
1013 	if (resp_uri)
1014 		wpa_printf(MSG_INFO, "RespURI: %s", resp_uri);
1015 
1016 	syncml = oma_dm_build_hdr(ctx, resp_uri ? resp_uri : url, msgid);
1017 	if (syncml == NULL) {
1018 		os_free(resp_uri);
1019 		return NULL;
1020 	}
1021 
1022 	syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody");
1023 	cmdid++;
1024 	add_status(ctx, syncbody, server_msgid, 0, cmdid, "SyncHdr",
1025 		   DM_RESP_AUTH_ACCEPTED, NULL);
1026 
1027 	xml_node_for_each_child(ctx->xml, child, body) {
1028 		xml_node_for_each_check(ctx->xml, child);
1029 		server_cmdid = oma_dm_get_cmdid(ctx, child);
1030 		name = xml_node_get_localname(ctx->xml, child);
1031 		wpa_printf(MSG_INFO, "SyncBody CmdID=%d - %s",
1032 			   server_cmdid, name);
1033 		if (os_strcasecmp(name, "Exec") == 0) {
1034 			int res = oma_dm_exec(ctx, child);
1035 			cmdid++;
1036 			locuri = oma_dm_get_target_locuri(ctx, child);
1037 			if (locuri == NULL)
1038 				res = DM_RESP_BAD_REQUEST;
1039 			add_status(ctx, syncbody, server_msgid, server_cmdid,
1040 				   cmdid, name, res, locuri);
1041 			os_free(locuri);
1042 			resp_needed = 1;
1043 		} else if (os_strcasecmp(name, "Add") == 0) {
1044 			int res = oma_dm_add(ctx, child, pps, pps_fname);
1045 			cmdid++;
1046 			locuri = oma_dm_get_target_locuri(ctx, child);
1047 			if (locuri == NULL)
1048 				res = DM_RESP_BAD_REQUEST;
1049 			add_status(ctx, syncbody, server_msgid, server_cmdid,
1050 				   cmdid, name, res, locuri);
1051 			os_free(locuri);
1052 			resp_needed = 1;
1053 		} else if (os_strcasecmp(name, "Replace") == 0) {
1054 			int res;
1055 			res = oma_dm_replace(ctx, child, pps, pps_fname);
1056 			cmdid++;
1057 			locuri = oma_dm_get_target_locuri(ctx, child);
1058 			if (locuri == NULL)
1059 				res = DM_RESP_BAD_REQUEST;
1060 			add_status(ctx, syncbody, server_msgid, server_cmdid,
1061 				   cmdid, name, res, locuri);
1062 			os_free(locuri);
1063 			resp_needed = 1;
1064 		} else if (os_strcasecmp(name, "Status") == 0) {
1065 			/* TODO: Verify success */
1066 		} else if (os_strcasecmp(name, "Get") == 0) {
1067 			int res;
1068 			char *value;
1069 			res = oma_dm_get(ctx, child, pps, pps_fname, &value);
1070 			cmdid++;
1071 			locuri = oma_dm_get_target_locuri(ctx, child);
1072 			if (locuri == NULL)
1073 				res = DM_RESP_BAD_REQUEST;
1074 			add_status(ctx, syncbody, server_msgid, server_cmdid,
1075 				   cmdid, name, res, locuri);
1076 			if (res == DM_RESP_OK && value) {
1077 				cmdid++;
1078 				add_results(ctx, syncbody, server_msgid,
1079 					    server_cmdid, cmdid, locuri, value);
1080 			}
1081 			os_free(locuri);
1082 			xml_node_get_text_free(ctx->xml, value);
1083 			resp_needed = 1;
1084 #if 0 /* TODO: MUST support */
1085 		} else if (os_strcasecmp(name, "Delete") == 0) {
1086 #endif
1087 #if 0 /* TODO: MUST support */
1088 		} else if (os_strcasecmp(name, "Sequence") == 0) {
1089 #endif
1090 		} else if (os_strcasecmp(name, "Final") == 0) {
1091 			final = 1;
1092 			break;
1093 		} else {
1094 			locuri = oma_dm_get_target_locuri(ctx, child);
1095 			add_status(ctx, syncbody, server_msgid, server_cmdid,
1096 				   cmdid, name, DM_RESP_COMMAND_NOT_IMPLEMENTED,
1097 				   locuri);
1098 			os_free(locuri);
1099 			resp_needed = 1;
1100 		}
1101 	}
1102 
1103 	if (!final) {
1104 		wpa_printf(MSG_INFO, "Final node not found");
1105 		xml_node_free(ctx->xml, syncml);
1106 		os_free(resp_uri);
1107 		return NULL;
1108 	}
1109 
1110 	if (!resp_needed) {
1111 		wpa_printf(MSG_INFO, "Exchange completed - no response needed");
1112 		xml_node_free(ctx->xml, syncml);
1113 		os_free(resp_uri);
1114 		return NULL;
1115 	}
1116 
1117 	xml_node_create(ctx->xml, syncbody, NULL, "Final");
1118 
1119 	debug_dump_node(ctx, "OMA-DM Package 3", syncml);
1120 
1121 	*ret_resp_uri = resp_uri;
1122 	return syncml;
1123 }
1124 
1125 
cmd_oma_dm_prov(struct hs20_osu_client * ctx,const char * url)1126 int cmd_oma_dm_prov(struct hs20_osu_client *ctx, const char *url)
1127 {
1128 	xml_node_t *syncml, *resp;
1129 	char *resp_uri = NULL;
1130 	int msgid = 0;
1131 
1132 	if (url == NULL) {
1133 		wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
1134 		return -1;
1135 	}
1136 
1137 	wpa_printf(MSG_INFO, "OMA-DM credential provisioning requested");
1138 	write_summary(ctx, "OMA-DM credential provisioning");
1139 
1140 	msgid++;
1141 	syncml = build_oma_dm_1_sub_reg(ctx, url, msgid);
1142 	if (syncml == NULL)
1143 		return -1;
1144 
1145 	while (syncml) {
1146 		resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url,
1147 					syncml, NULL, NULL, NULL, NULL, NULL);
1148 		if (resp == NULL)
1149 			return -1;
1150 
1151 		msgid++;
1152 		syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri,
1153 					NULL, NULL);
1154 		xml_node_free(ctx->xml, resp);
1155 	}
1156 
1157 	os_free(resp_uri);
1158 
1159 	return ctx->pps_cred_set ? 0 : -1;
1160 }
1161 
1162 
cmd_oma_dm_sim_prov(struct hs20_osu_client * ctx,const char * url)1163 int cmd_oma_dm_sim_prov(struct hs20_osu_client *ctx, const char *url)
1164 {
1165 	xml_node_t *syncml, *resp;
1166 	char *resp_uri = NULL;
1167 	int msgid = 0;
1168 
1169 	if (url == NULL) {
1170 		wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
1171 		return -1;
1172 	}
1173 
1174 	wpa_printf(MSG_INFO, "OMA-DM SIM provisioning requested");
1175 	ctx->no_reconnect = 2;
1176 
1177 	wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning");
1178 	write_summary(ctx, "Wait for IP address before starting SIM provisioning");
1179 
1180 	if (wait_ip_addr(ctx->ifname, 15) < 0) {
1181 		wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
1182 	}
1183 	write_summary(ctx, "OMA-DM SIM provisioning");
1184 
1185 	msgid++;
1186 	syncml = build_oma_dm_1_sub_prov(ctx, url, msgid);
1187 	if (syncml == NULL)
1188 		return -1;
1189 
1190 	while (syncml) {
1191 		resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url,
1192 					syncml, NULL, NULL, NULL, NULL, NULL);
1193 		if (resp == NULL)
1194 			return -1;
1195 
1196 		msgid++;
1197 		syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri,
1198 					NULL, NULL);
1199 		xml_node_free(ctx->xml, resp);
1200 	}
1201 
1202 	os_free(resp_uri);
1203 
1204 	if (ctx->pps_cred_set) {
1205 		wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
1206 		cmd_set_pps(ctx, ctx->pps_fname);
1207 
1208 		wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
1209 		write_summary(ctx, "Requesting reconnection with updated configuration");
1210 		if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
1211 			wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
1212 			write_summary(ctx, "Failed to request wpa_supplicant to reconnect");
1213 			return -1;
1214 		}
1215 	}
1216 
1217 	return ctx->pps_cred_set ? 0 : -1;
1218 }
1219 
1220 
oma_dm_pol_upd(struct hs20_osu_client * ctx,const char * address,const char * pps_fname,const char * client_cert,const char * client_key,const char * cred_username,const char * cred_password,xml_node_t * pps)1221 void oma_dm_pol_upd(struct hs20_osu_client *ctx, const char *address,
1222 		    const char *pps_fname,
1223 		    const char *client_cert, const char *client_key,
1224 		    const char *cred_username, const char *cred_password,
1225 		    xml_node_t *pps)
1226 {
1227 	xml_node_t *syncml, *resp;
1228 	char *resp_uri = NULL;
1229 	int msgid = 0;
1230 
1231 	wpa_printf(MSG_INFO, "OMA-DM policy update");
1232 	write_summary(ctx, "OMA-DM policy update");
1233 
1234 	msgid++;
1235 	syncml = build_oma_dm_1_pol_upd(ctx, address, msgid);
1236 	if (syncml == NULL)
1237 		return;
1238 
1239 	while (syncml) {
1240 		resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address,
1241 					syncml, NULL, cred_username,
1242 					cred_password, client_cert, client_key);
1243 		if (resp == NULL)
1244 			return;
1245 
1246 		msgid++;
1247 		syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri,
1248 					pps, pps_fname);
1249 		xml_node_free(ctx->xml, resp);
1250 	}
1251 
1252 	os_free(resp_uri);
1253 
1254 	if (ctx->pps_updated) {
1255 		wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO");
1256 		write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request connection");
1257 		cmd_set_pps(ctx, pps_fname);
1258 		if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
1259 			wpa_printf(MSG_INFO,
1260 				   "Failed to request wpa_supplicant to reconnect");
1261 			write_summary(ctx,
1262 				      "Failed to request wpa_supplicant to reconnect");
1263 		}
1264 	}
1265 }
1266 
1267 
oma_dm_sub_rem(struct hs20_osu_client * ctx,const char * address,const char * pps_fname,const char * client_cert,const char * client_key,const char * cred_username,const char * cred_password,xml_node_t * pps)1268 void oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address,
1269 		    const char *pps_fname,
1270 		    const char *client_cert, const char *client_key,
1271 		    const char *cred_username, const char *cred_password,
1272 		    xml_node_t *pps)
1273 {
1274 	xml_node_t *syncml, *resp;
1275 	char *resp_uri = NULL;
1276 	int msgid = 0;
1277 
1278 	wpa_printf(MSG_INFO, "OMA-DM subscription remediation");
1279 	write_summary(ctx, "OMA-DM subscription remediation");
1280 
1281 	msgid++;
1282 	syncml = build_oma_dm_1_sub_rem(ctx, address, msgid);
1283 	if (syncml == NULL)
1284 		return;
1285 
1286 	while (syncml) {
1287 		resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address,
1288 					syncml, NULL, cred_username,
1289 					cred_password, client_cert, client_key);
1290 		if (resp == NULL)
1291 			return;
1292 
1293 		msgid++;
1294 		syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri,
1295 					pps, pps_fname);
1296 		xml_node_free(ctx->xml, resp);
1297 	}
1298 
1299 	os_free(resp_uri);
1300 
1301 	wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO and request reconnection");
1302 	write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request reconnection");
1303 	cmd_set_pps(ctx, pps_fname);
1304 	if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
1305 		wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
1306 		write_summary(ctx, "Failed to request wpa_supplicant to reconnect");
1307 	}
1308 }
1309 
1310 
cmd_oma_dm_add(struct hs20_osu_client * ctx,const char * pps_fname,const char * add_fname)1311 void cmd_oma_dm_add(struct hs20_osu_client *ctx, const char *pps_fname,
1312 		    const char *add_fname)
1313 {
1314 	xml_node_t *pps, *add;
1315 	int res;
1316 
1317 	ctx->fqdn = os_strdup("wi-fi.org");
1318 
1319 	pps = node_from_file(ctx->xml, pps_fname);
1320 	if (pps == NULL) {
1321 		wpa_printf(MSG_INFO, "PPS file %s could not be parsed",
1322 			   pps_fname);
1323 		return;
1324 	}
1325 
1326 	add = node_from_file(ctx->xml, add_fname);
1327 	if (add == NULL) {
1328 		wpa_printf(MSG_INFO, "Add file %s could not be parsed",
1329 			   add_fname);
1330 		xml_node_free(ctx->xml, pps);
1331 		return;
1332 	}
1333 
1334 	res = oma_dm_add(ctx, add, pps, pps_fname);
1335 	wpa_printf(MSG_INFO, "oma_dm_add --> %d", res);
1336 
1337 	xml_node_free(ctx->xml, pps);
1338 	xml_node_free(ctx->xml, add);
1339 }
1340 
1341 
cmd_oma_dm_replace(struct hs20_osu_client * ctx,const char * pps_fname,const char * replace_fname)1342 void cmd_oma_dm_replace(struct hs20_osu_client *ctx, const char *pps_fname,
1343 			const char *replace_fname)
1344 {
1345 	xml_node_t *pps, *replace;
1346 	int res;
1347 
1348 	ctx->fqdn = os_strdup("wi-fi.org");
1349 
1350 	pps = node_from_file(ctx->xml, pps_fname);
1351 	if (pps == NULL) {
1352 		wpa_printf(MSG_INFO, "PPS file %s could not be parsed",
1353 			   pps_fname);
1354 		return;
1355 	}
1356 
1357 	replace = node_from_file(ctx->xml, replace_fname);
1358 	if (replace == NULL) {
1359 		wpa_printf(MSG_INFO, "Replace file %s could not be parsed",
1360 			   replace_fname);
1361 		xml_node_free(ctx->xml, pps);
1362 		return;
1363 	}
1364 
1365 	res = oma_dm_replace(ctx, replace, pps, pps_fname);
1366 	wpa_printf(MSG_INFO, "oma_dm_replace --> %d", res);
1367 
1368 	xml_node_free(ctx->xml, pps);
1369 	xml_node_free(ctx->xml, replace);
1370 }
1371