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