blob: 4d77d0e86e390df0ad5d29b4d3db9a60152fa54f [file] [log] [blame]
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001/*
2 * Hotspot 2.0 SPP server
3 * Copyright (c) 2012-2013, 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 <stdlib.h>
10#include <stdio.h>
11#include <string.h>
12#include <ctype.h>
13#include <time.h>
14#include <errno.h>
15#include <sqlite3.h>
16
17#include "common.h"
18#include "base64.h"
19#include "md5_i.h"
20#include "xml-utils.h"
21#include "spp_server.h"
22
23
24#define SPP_NS_URI "http://www.wi-fi.org/specifications/hotspot2dot0/v1.0/spp"
25
26#define URN_OMA_DM_DEVINFO "urn:oma:mo:oma-dm-devinfo:1.0"
27#define URN_OMA_DM_DEVDETAIL "urn:oma:mo:oma-dm-devdetail:1.0"
28#define URN_OMA_DM_DMACC "urn:oma:mo:oma-dm-dmacc:1.0"
29#define URN_HS20_PPS "urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0"
30
31
32/* TODO: timeout to expire sessions */
33
34enum hs20_session_operation {
35 NO_OPERATION,
36 UPDATE_PASSWORD,
37 CONTINUE_SUBSCRIPTION_REMEDIATION,
38 CONTINUE_POLICY_UPDATE,
39 USER_REMEDIATION,
40 SUBSCRIPTION_REGISTRATION,
41 POLICY_REMEDIATION,
42 POLICY_UPDATE,
43 FREE_REMEDIATION,
44};
45
46
47static char * db_get_session_val(struct hs20_svc *ctx, const char *user,
48 const char *realm, const char *session_id,
49 const char *field);
50static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm,
51 const char *field);
52static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
53 const char *realm, int use_dmacc);
54
55
56static int db_add_session(struct hs20_svc *ctx,
57 const char *user, const char *realm,
58 const char *sessionid, const char *pw,
59 const char *redirect_uri,
60 enum hs20_session_operation operation)
61{
62 char *sql;
63 int ret = 0;
64
65 sql = sqlite3_mprintf("INSERT INTO sessions(timestamp,id,user,realm,"
66 "operation,password,redirect_uri) "
67 "VALUES "
68 "(strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
69 "%Q,%Q,%Q,%d,%Q,%Q)",
70 sessionid, user ? user : "", realm ? realm : "",
71 operation, pw ? pw : "",
72 redirect_uri ? redirect_uri : "");
73 if (sql == NULL)
74 return -1;
75 debug_print(ctx, 1, "DB: %s", sql);
76 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
77 debug_print(ctx, 1, "Failed to add session entry into sqlite "
78 "database: %s", sqlite3_errmsg(ctx->db));
79 ret = -1;
80 }
81 sqlite3_free(sql);
82 return ret;
83}
84
85
86static void db_update_session_password(struct hs20_svc *ctx, const char *user,
87 const char *realm, const char *sessionid,
88 const char *pw)
89{
90 char *sql;
91
92 sql = sqlite3_mprintf("UPDATE sessions SET password=%Q WHERE id=%Q AND "
93 "user=%Q AND realm=%Q",
94 pw, sessionid, user, realm);
95 if (sql == NULL)
96 return;
97 debug_print(ctx, 1, "DB: %s", sql);
98 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
99 debug_print(ctx, 1, "Failed to update session password: %s",
100 sqlite3_errmsg(ctx->db));
101 }
102 sqlite3_free(sql);
103}
104
105
106static void db_add_session_pps(struct hs20_svc *ctx, const char *user,
107 const char *realm, const char *sessionid,
108 xml_node_t *node)
109{
110 char *str;
111 char *sql;
112
113 str = xml_node_to_str(ctx->xml, node);
114 if (str == NULL)
115 return;
116 sql = sqlite3_mprintf("UPDATE sessions SET pps=%Q WHERE id=%Q AND "
117 "user=%Q AND realm=%Q",
118 str, sessionid, user, realm);
119 free(str);
120 if (sql == NULL)
121 return;
122 debug_print(ctx, 1, "DB: %s", sql);
123 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
124 debug_print(ctx, 1, "Failed to add session pps: %s",
125 sqlite3_errmsg(ctx->db));
126 }
127 sqlite3_free(sql);
128}
129
130
131static void db_add_session_devinfo(struct hs20_svc *ctx, const char *sessionid,
132 xml_node_t *node)
133{
134 char *str;
135 char *sql;
136
137 str = xml_node_to_str(ctx->xml, node);
138 if (str == NULL)
139 return;
140 sql = sqlite3_mprintf("UPDATE sessions SET devinfo=%Q WHERE id=%Q",
141 str, sessionid);
142 free(str);
143 if (sql == NULL)
144 return;
145 debug_print(ctx, 1, "DB: %s", sql);
146 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
147 debug_print(ctx, 1, "Failed to add session devinfo: %s",
148 sqlite3_errmsg(ctx->db));
149 }
150 sqlite3_free(sql);
151}
152
153
154static void db_add_session_devdetail(struct hs20_svc *ctx,
155 const char *sessionid,
156 xml_node_t *node)
157{
158 char *str;
159 char *sql;
160
161 str = xml_node_to_str(ctx->xml, node);
162 if (str == NULL)
163 return;
164 sql = sqlite3_mprintf("UPDATE sessions SET devdetail=%Q WHERE id=%Q",
165 str, sessionid);
166 free(str);
167 if (sql == NULL)
168 return;
169 debug_print(ctx, 1, "DB: %s", sql);
170 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
171 debug_print(ctx, 1, "Failed to add session devdetail: %s",
172 sqlite3_errmsg(ctx->db));
173 }
174 sqlite3_free(sql);
175}
176
177
178static void db_remove_session(struct hs20_svc *ctx,
179 const char *user, const char *realm,
180 const char *sessionid)
181{
182 char *sql;
183
184 if (user == NULL || realm == NULL) {
185 sql = sqlite3_mprintf("DELETE FROM sessions WHERE "
186 "id=%Q", sessionid);
187 } else {
188 sql = sqlite3_mprintf("DELETE FROM sessions WHERE "
189 "user=%Q AND realm=%Q AND id=%Q",
190 user, realm, sessionid);
191 }
192 if (sql == NULL)
193 return;
194 debug_print(ctx, 1, "DB: %s", sql);
195 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
196 debug_print(ctx, 1, "Failed to delete session entry from "
197 "sqlite database: %s", sqlite3_errmsg(ctx->db));
198 }
199 sqlite3_free(sql);
200}
201
202
203static void hs20_eventlog(struct hs20_svc *ctx,
204 const char *user, const char *realm,
205 const char *sessionid, const char *notes,
206 const char *dump)
207{
208 char *sql;
209 char *user_buf = NULL, *realm_buf = NULL;
210
211 debug_print(ctx, 1, "eventlog: %s", notes);
212
213 if (user == NULL) {
214 user_buf = db_get_session_val(ctx, NULL, NULL, sessionid,
215 "user");
216 user = user_buf;
217 realm_buf = db_get_session_val(ctx, NULL, NULL, sessionid,
218 "realm");
219 realm = realm_buf;
220 }
221
222 sql = sqlite3_mprintf("INSERT INTO eventlog"
223 "(user,realm,sessionid,timestamp,notes,dump,addr)"
224 " VALUES (%Q,%Q,%Q,"
225 "strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
226 "%Q,%Q,%Q)",
227 user, realm, sessionid, notes,
228 dump ? dump : "", ctx->addr ? ctx->addr : "");
229 free(user_buf);
230 free(realm_buf);
231 if (sql == NULL)
232 return;
233 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
234 debug_print(ctx, 1, "Failed to add eventlog entry into sqlite "
235 "database: %s", sqlite3_errmsg(ctx->db));
236 }
237 sqlite3_free(sql);
238}
239
240
241static void hs20_eventlog_node(struct hs20_svc *ctx,
242 const char *user, const char *realm,
243 const char *sessionid, const char *notes,
244 xml_node_t *node)
245{
246 char *str;
247
248 if (node)
249 str = xml_node_to_str(ctx->xml, node);
250 else
251 str = NULL;
252 hs20_eventlog(ctx, user, realm, sessionid, notes, str);
253 free(str);
254}
255
256
257static void db_update_mo_str(struct hs20_svc *ctx, const char *user,
258 const char *realm, const char *name,
259 const char *str)
260{
261 char *sql;
262 if (user == NULL || realm == NULL || name == NULL)
263 return;
264 sql = sqlite3_mprintf("UPDATE users SET %s=%Q "
265 "WHERE identity=%Q AND realm=%Q AND phase2=1",
266 name, str, user, realm);
267 if (sql == NULL)
268 return;
269 debug_print(ctx, 1, "DB: %s", sql);
270 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
271 debug_print(ctx, 1, "Failed to update user MO entry in sqlite "
272 "database: %s", sqlite3_errmsg(ctx->db));
273 }
274 sqlite3_free(sql);
275}
276
277
278static void db_update_mo(struct hs20_svc *ctx, const char *user,
279 const char *realm, const char *name, xml_node_t *mo)
280{
281 char *str;
282
283 str = xml_node_to_str(ctx->xml, mo);
284 if (str == NULL)
285 return;
286
287 db_update_mo_str(ctx, user, realm, name, str);
288 free(str);
289}
290
291
292static void add_text_node(struct hs20_svc *ctx, xml_node_t *parent,
293 const char *name, const char *value)
294{
295 xml_node_create_text(ctx->xml, parent, NULL, name, value ? value : "");
296}
297
298
299static void add_text_node_conf(struct hs20_svc *ctx, const char *realm,
300 xml_node_t *parent, const char *name,
301 const char *field)
302{
303 char *val;
304 val = db_get_osu_config_val(ctx, realm, field);
305 xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : "");
306 os_free(val);
307}
308
309
310static int new_password(char *buf, int buflen)
311{
312 int i;
313
314 if (buflen < 1)
315 return -1;
316 buf[buflen - 1] = '\0';
317 if (os_get_random((unsigned char *) buf, buflen - 1) < 0)
318 return -1;
319
320 for (i = 0; i < buflen - 1; i++) {
321 unsigned char val = buf[i];
322 val %= 2 * 26 + 10;
323 if (val < 26)
324 buf[i] = 'a' + val;
325 else if (val < 2 * 26)
326 buf[i] = 'A' + val - 26;
327 else
328 buf[i] = '0' + val - 2 * 26;
329 }
330
331 return 0;
332}
333
334
335struct get_db_field_data {
336 const char *field;
337 char *value;
338};
339
340
341static int get_db_field(void *ctx, int argc, char *argv[], char *col[])
342{
343 struct get_db_field_data *data = ctx;
344 int i;
345
346 for (i = 0; i < argc; i++) {
347 if (os_strcmp(col[i], data->field) == 0 && argv[i]) {
348 os_free(data->value);
349 data->value = os_strdup(argv[i]);
350 break;
351 }
352 }
353
354 return 0;
355}
356
357
358static char * db_get_val(struct hs20_svc *ctx, const char *user,
359 const char *realm, const char *field, int dmacc)
360{
361 char *cmd;
362 struct get_db_field_data data;
363
364 cmd = sqlite3_mprintf("SELECT %s FROM users WHERE "
365 "%s=%Q AND realm=%Q AND phase2=1",
366 field, dmacc ? "osu_user" : "identity",
367 user, realm);
368 if (cmd == NULL)
369 return NULL;
370 memset(&data, 0, sizeof(data));
371 data.field = field;
372 if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
373 {
374 debug_print(ctx, 1, "Could not find user '%s'", user);
375 sqlite3_free(cmd);
376 return NULL;
377 }
378 sqlite3_free(cmd);
379
380 debug_print(ctx, 1, "DB: user='%s' realm='%s' field='%s' dmacc=%d --> "
381 "value='%s'", user, realm, field, dmacc, data.value);
382
383 return data.value;
384}
385
386
387static int db_update_val(struct hs20_svc *ctx, const char *user,
388 const char *realm, const char *field,
389 const char *val, int dmacc)
390{
391 char *cmd;
392 int ret;
393
394 cmd = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE "
395 "%s=%Q AND realm=%Q AND phase2=1",
396 field, val, dmacc ? "osu_user" : "identity", user,
397 realm);
398 if (cmd == NULL)
399 return -1;
400 debug_print(ctx, 1, "DB: %s", cmd);
401 if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
402 debug_print(ctx, 1,
403 "Failed to update user in sqlite database: %s",
404 sqlite3_errmsg(ctx->db));
405 ret = -1;
406 } else {
407 debug_print(ctx, 1,
408 "DB: user='%s' realm='%s' field='%s' set to '%s'",
409 user, realm, field, val);
410 ret = 0;
411 }
412 sqlite3_free(cmd);
413
414 return ret;
415}
416
417
418static char * db_get_session_val(struct hs20_svc *ctx, const char *user,
419 const char *realm, const char *session_id,
420 const char *field)
421{
422 char *cmd;
423 struct get_db_field_data data;
424
425 if (user == NULL || realm == NULL) {
426 cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE "
427 "id=%Q", field, session_id);
428 } else {
429 cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE "
430 "user=%Q AND realm=%Q AND id=%Q",
431 field, user, realm, session_id);
432 }
433 if (cmd == NULL)
434 return NULL;
435 debug_print(ctx, 1, "DB: %s", cmd);
436 memset(&data, 0, sizeof(data));
437 data.field = field;
438 if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
439 {
440 debug_print(ctx, 1, "DB: Could not find session %s: %s",
441 session_id, sqlite3_errmsg(ctx->db));
442 sqlite3_free(cmd);
443 return NULL;
444 }
445 sqlite3_free(cmd);
446
447 debug_print(ctx, 1, "DB: return '%s'", data.value);
448 return data.value;
449}
450
451
452static int update_password(struct hs20_svc *ctx, const char *user,
453 const char *realm, const char *pw, int dmacc)
454{
455 char *cmd;
456
457 cmd = sqlite3_mprintf("UPDATE users SET password=%Q, "
458 "remediation='' "
459 "WHERE %s=%Q AND phase2=1",
460 pw, dmacc ? "osu_user" : "identity",
461 user);
462 if (cmd == NULL)
463 return -1;
464 debug_print(ctx, 1, "DB: %s", cmd);
465 if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
466 debug_print(ctx, 1, "Failed to update database for user '%s'",
467 user);
468 }
469 sqlite3_free(cmd);
470
471 return 0;
472}
473
474
475static int add_eap_ttls(struct hs20_svc *ctx, xml_node_t *parent)
476{
477 xml_node_t *node;
478
479 node = xml_node_create(ctx->xml, parent, NULL, "EAPMethod");
480 if (node == NULL)
481 return -1;
482
483 add_text_node(ctx, node, "EAPType", "21");
484 add_text_node(ctx, node, "InnerMethod", "MS-CHAP-V2");
485
486 return 0;
487}
488
489
490static xml_node_t * build_username_password(struct hs20_svc *ctx,
491 xml_node_t *parent,
492 const char *user, const char *pw)
493{
494 xml_node_t *node;
495 char *b64;
496
497 node = xml_node_create(ctx->xml, parent, NULL, "UsernamePassword");
498 if (node == NULL)
499 return NULL;
500
501 add_text_node(ctx, node, "Username", user);
502
503 b64 = (char *) base64_encode((unsigned char *) pw, strlen(pw), NULL);
504 if (b64 == NULL)
505 return NULL;
506 add_text_node(ctx, node, "Password", b64);
507 free(b64);
508
509 return node;
510}
511
512
513static int add_username_password(struct hs20_svc *ctx, xml_node_t *cred,
514 const char *user, const char *pw)
515{
516 xml_node_t *node;
517
518 node = build_username_password(ctx, cred, user, pw);
519 if (node == NULL)
520 return -1;
521
522 add_text_node(ctx, node, "MachineManaged", "TRUE");
523 add_text_node(ctx, node, "SoftTokenApp", "");
524 add_eap_ttls(ctx, node);
525
526 return 0;
527}
528
529
530static void add_creation_date(struct hs20_svc *ctx, xml_node_t *cred)
531{
532 char str[30];
533 time_t now;
534 struct tm tm;
535
536 time(&now);
537 gmtime_r(&now, &tm);
538 snprintf(str, sizeof(str), "%04u-%02u-%02uT%02u:%02u:%02uZ",
539 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
540 tm.tm_hour, tm.tm_min, tm.tm_sec);
541 xml_node_create_text(ctx->xml, cred, NULL, "CreationDate", str);
542}
543
544
545static xml_node_t * build_credential_pw(struct hs20_svc *ctx,
546 const char *user, const char *realm,
547 const char *pw)
548{
549 xml_node_t *cred;
550
551 cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential");
552 if (cred == NULL) {
553 debug_print(ctx, 1, "Failed to create Credential node");
554 return NULL;
555 }
556 add_creation_date(ctx, cred);
557 if (add_username_password(ctx, cred, user, pw) < 0) {
558 xml_node_free(ctx->xml, cred);
559 return NULL;
560 }
561 add_text_node(ctx, cred, "Realm", realm);
562
563 return cred;
564}
565
566
567static xml_node_t * build_credential(struct hs20_svc *ctx,
568 const char *user, const char *realm,
569 char *new_pw, size_t new_pw_len)
570{
571 if (new_password(new_pw, new_pw_len) < 0)
572 return NULL;
573 debug_print(ctx, 1, "Update password to '%s'", new_pw);
574 return build_credential_pw(ctx, user, realm, new_pw);
575}
576
577
578static xml_node_t * build_credential_cert(struct hs20_svc *ctx,
579 const char *user, const char *realm,
580 const char *cert_fingerprint)
581{
582 xml_node_t *cred, *cert;
583
584 cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential");
585 if (cred == NULL) {
586 debug_print(ctx, 1, "Failed to create Credential node");
587 return NULL;
588 }
589 add_creation_date(ctx, cred);
590 cert = xml_node_create(ctx->xml, cred, NULL, "DigitalCertificate");
591 add_text_node(ctx, cert, "CertificateType", "x509v3");
592 add_text_node(ctx, cert, "CertSHA256Fingerprint", cert_fingerprint);
593 add_text_node(ctx, cred, "Realm", realm);
594
595 return cred;
596}
597
598
599static xml_node_t * build_post_dev_data_response(struct hs20_svc *ctx,
600 xml_namespace_t **ret_ns,
601 const char *session_id,
602 const char *status,
603 const char *error_code)
604{
605 xml_node_t *spp_node = NULL;
606 xml_namespace_t *ns;
607
608 spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
609 "sppPostDevDataResponse");
610 if (spp_node == NULL)
611 return NULL;
612 if (ret_ns)
613 *ret_ns = ns;
614
615 xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
616 xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
617 xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
618
619 if (error_code) {
620 xml_node_t *node;
621 node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
622 if (node)
623 xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
624 error_code);
625 }
626
627 return spp_node;
628}
629
630
631static int add_update_node(struct hs20_svc *ctx, xml_node_t *spp_node,
632 xml_namespace_t *ns, const char *uri,
633 xml_node_t *upd_node)
634{
635 xml_node_t *node, *tnds;
636 char *str;
637
638 tnds = mo_to_tnds(ctx->xml, upd_node, 0, NULL, NULL);
639 if (!tnds)
640 return -1;
641
642 str = xml_node_to_str(ctx->xml, tnds);
643 xml_node_free(ctx->xml, tnds);
644 if (str == NULL)
645 return -1;
646 node = xml_node_create_text(ctx->xml, spp_node, ns, "updateNode", str);
647 free(str);
648
649 xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", uri);
650
651 return 0;
652}
653
654
655static xml_node_t * build_sub_rem_resp(struct hs20_svc *ctx,
656 const char *user, const char *realm,
657 const char *session_id,
658 int machine_rem, int dmacc)
659{
660 xml_namespace_t *ns;
661 xml_node_t *spp_node, *cred;
662 char buf[400];
663 char new_pw[33];
664 char *real_user = NULL;
665 char *status;
666 char *cert;
667
668 if (dmacc) {
669 real_user = db_get_val(ctx, user, realm, "identity", dmacc);
670 if (real_user == NULL) {
671 debug_print(ctx, 1, "Could not find user identity for "
672 "dmacc user '%s'", user);
673 return NULL;
674 }
675 }
676
677 cert = db_get_val(ctx, user, realm, "cert", dmacc);
678 if (cert && cert[0] == '\0')
679 cert = NULL;
680 if (cert) {
681 cred = build_credential_cert(ctx, real_user ? real_user : user,
682 realm, cert);
683 } else {
684 cred = build_credential(ctx, real_user ? real_user : user,
685 realm, new_pw, sizeof(new_pw));
686 }
687 free(real_user);
688 if (!cred) {
689 debug_print(ctx, 1, "Could not build credential");
690 return NULL;
691 }
692
693 status = "Remediation complete, request sppUpdateResponse";
694 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
695 NULL);
696 if (spp_node == NULL) {
697 debug_print(ctx, 1, "Could not build sppPostDevDataResponse");
698 return NULL;
699 }
700
701 snprintf(buf, sizeof(buf),
702 "./Wi-Fi/%s/PerProviderSubscription/Credential1/Credential",
703 realm);
704
705 if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
706 debug_print(ctx, 1, "Could not add update node");
707 xml_node_free(ctx->xml, spp_node);
708 return NULL;
709 }
710
711 hs20_eventlog_node(ctx, user, realm, session_id,
712 machine_rem ? "machine remediation" :
713 "user remediation", cred);
714 xml_node_free(ctx->xml, cred);
715
716 if (cert) {
717 debug_print(ctx, 1, "Certificate credential - no need for DB "
718 "password update on success notification");
719 } else {
720 debug_print(ctx, 1, "Request DB password update on success "
721 "notification");
722 db_add_session(ctx, user, realm, session_id, new_pw, NULL,
723 UPDATE_PASSWORD);
724 }
725
726 return spp_node;
727}
728
729
730static xml_node_t * machine_remediation(struct hs20_svc *ctx,
731 const char *user,
732 const char *realm,
733 const char *session_id, int dmacc)
734{
735 return build_sub_rem_resp(ctx, user, realm, session_id, 1, dmacc);
736}
737
738
739static xml_node_t * policy_remediation(struct hs20_svc *ctx,
740 const char *user, const char *realm,
741 const char *session_id, int dmacc)
742{
743 xml_namespace_t *ns;
744 xml_node_t *spp_node, *policy;
745 char buf[400];
746 const char *status;
747
748 hs20_eventlog(ctx, user, realm, session_id,
749 "requires policy remediation", NULL);
750
751 db_add_session(ctx, user, realm, session_id, NULL, NULL,
752 POLICY_REMEDIATION);
753
754 policy = build_policy(ctx, user, realm, dmacc);
755 if (!policy) {
756 return build_post_dev_data_response(
757 ctx, NULL, session_id,
758 "No update available at this time", NULL);
759 }
760
761 status = "Remediation complete, request sppUpdateResponse";
762 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
763 NULL);
764 if (spp_node == NULL)
765 return NULL;
766
767 snprintf(buf, sizeof(buf),
768 "./Wi-Fi/%s/PerProviderSubscription/Credential1/Policy",
769 realm);
770
771 if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
772 xml_node_free(ctx->xml, spp_node);
773 xml_node_free(ctx->xml, policy);
774 return NULL;
775 }
776
777 hs20_eventlog_node(ctx, user, realm, session_id,
778 "policy update (sub rem)", policy);
779 xml_node_free(ctx->xml, policy);
780
781 return spp_node;
782}
783
784
785static xml_node_t * browser_remediation(struct hs20_svc *ctx,
786 const char *session_id,
787 const char *redirect_uri,
788 const char *uri)
789{
790 xml_namespace_t *ns;
791 xml_node_t *spp_node, *exec_node;
792
793 if (redirect_uri == NULL) {
794 debug_print(ctx, 1, "Missing redirectURI attribute for user "
795 "remediation");
796 return NULL;
797 }
798 debug_print(ctx, 1, "redirectURI %s", redirect_uri);
799
800 spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
801 NULL);
802 if (spp_node == NULL)
803 return NULL;
804
805 exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
806 xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI",
807 uri);
808 return spp_node;
809}
810
811
812static xml_node_t * user_remediation(struct hs20_svc *ctx, const char *user,
813 const char *realm, const char *session_id,
814 const char *redirect_uri)
815{
816 char uri[300], *val;
817
818 hs20_eventlog(ctx, user, realm, session_id,
819 "requires user remediation", NULL);
820 val = db_get_osu_config_val(ctx, realm, "remediation_url");
821 if (val == NULL)
822 return NULL;
823
824 db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
825 USER_REMEDIATION);
826
827 snprintf(uri, sizeof(uri), "%s%s", val, session_id);
828 os_free(val);
829 return browser_remediation(ctx, session_id, redirect_uri, uri);
830}
831
832
833static xml_node_t * free_remediation(struct hs20_svc *ctx,
834 const char *user, const char *realm,
835 const char *session_id,
836 const char *redirect_uri)
837{
838 char uri[300], *val;
839
840 hs20_eventlog(ctx, user, realm, session_id,
841 "requires free/public account remediation", NULL);
842 val = db_get_osu_config_val(ctx, realm, "free_remediation_url");
843 if (val == NULL)
844 return NULL;
845
846 db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
847 FREE_REMEDIATION);
848
849 snprintf(uri, sizeof(uri), "%s%s", val, session_id);
850 os_free(val);
851 return browser_remediation(ctx, session_id, redirect_uri, uri);
852}
853
854
855static xml_node_t * no_sub_rem(struct hs20_svc *ctx,
856 const char *user, const char *realm,
857 const char *session_id)
858{
859 const char *status;
860
861 hs20_eventlog(ctx, user, realm, session_id,
862 "no subscription mediation available", NULL);
863
864 status = "No update available at this time";
865 return build_post_dev_data_response(ctx, NULL, session_id, status,
866 NULL);
867}
868
869
870static xml_node_t * hs20_subscription_remediation(struct hs20_svc *ctx,
871 const char *user,
872 const char *realm,
873 const char *session_id,
874 int dmacc,
875 const char *redirect_uri)
876{
877 char *type, *identity;
878 xml_node_t *ret;
879 char *free_account;
880
881 identity = db_get_val(ctx, user, realm, "identity", dmacc);
882 if (identity == NULL || strlen(identity) == 0) {
883 hs20_eventlog(ctx, user, realm, session_id,
884 "user not found in database for remediation",
885 NULL);
886 os_free(identity);
887 return build_post_dev_data_response(ctx, NULL, session_id,
888 "Error occurred",
889 "Not found");
890 }
891 os_free(identity);
892
893 free_account = db_get_osu_config_val(ctx, realm, "free_account");
894 if (free_account && strcmp(free_account, user) == 0) {
895 free(free_account);
896 return no_sub_rem(ctx, user, realm, session_id);
897 }
898 free(free_account);
899
900 type = db_get_val(ctx, user, realm, "remediation", dmacc);
901 if (type && strcmp(type, "free") != 0) {
902 char *val;
903 int shared = 0;
904 val = db_get_val(ctx, user, realm, "shared", dmacc);
905 if (val)
906 shared = atoi(val);
907 free(val);
908 if (shared) {
909 free(type);
910 return no_sub_rem(ctx, user, realm, session_id);
911 }
912 }
913 if (type && strcmp(type, "user") == 0)
914 ret = user_remediation(ctx, user, realm, session_id,
915 redirect_uri);
916 else if (type && strcmp(type, "free") == 0)
917 ret = free_remediation(ctx, user, realm, session_id,
918 redirect_uri);
919 else if (type && strcmp(type, "policy") == 0)
920 ret = policy_remediation(ctx, user, realm, session_id, dmacc);
921 else
922 ret = machine_remediation(ctx, user, realm, session_id, dmacc);
923 free(type);
924
925 return ret;
926}
927
928
929static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
930 const char *realm, int use_dmacc)
931{
932 char *policy_id;
933 char fname[200];
934 xml_node_t *policy, *node;
935
936 policy_id = db_get_val(ctx, user, realm, "policy", use_dmacc);
937 if (policy_id == NULL || strlen(policy_id) == 0) {
938 free(policy_id);
939 policy_id = strdup("default");
940 if (policy_id == NULL)
941 return NULL;
942 }
943
944 snprintf(fname, sizeof(fname), "%s/spp/policy/%s.xml",
945 ctx->root_dir, policy_id);
946 free(policy_id);
947 debug_print(ctx, 1, "Use policy file %s", fname);
948
949 policy = node_from_file(ctx->xml, fname);
950 if (policy == NULL)
951 return NULL;
952
953 node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate/URI");
954 if (node) {
955 char *url;
956 url = db_get_osu_config_val(ctx, realm, "policy_url");
957 if (url == NULL) {
958 xml_node_free(ctx->xml, policy);
959 return NULL;
960 }
961 xml_node_set_text(ctx->xml, node, url);
962 free(url);
963 }
964
965 node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate");
966 if (node && use_dmacc) {
967 char *pw;
968 pw = db_get_val(ctx, user, realm, "osu_password", use_dmacc);
969 if (pw == NULL ||
970 build_username_password(ctx, node, user, pw) == NULL) {
971 debug_print(ctx, 1, "Failed to add Policy/PolicyUpdate/"
972 "UsernamePassword");
973 free(pw);
974 xml_node_free(ctx->xml, policy);
975 return NULL;
976 }
977 free(pw);
978 }
979
980 return policy;
981}
982
983
984static xml_node_t * hs20_policy_update(struct hs20_svc *ctx,
985 const char *user, const char *realm,
986 const char *session_id, int dmacc)
987{
988 xml_namespace_t *ns;
989 xml_node_t *spp_node;
990 xml_node_t *policy;
991 char buf[400];
992 const char *status;
993 char *identity;
994
995 identity = db_get_val(ctx, user, realm, "identity", dmacc);
996 if (identity == NULL || strlen(identity) == 0) {
997 hs20_eventlog(ctx, user, realm, session_id,
998 "user not found in database for policy update",
999 NULL);
1000 os_free(identity);
1001 return build_post_dev_data_response(ctx, NULL, session_id,
1002 "Error occurred",
1003 "Not found");
1004 }
1005 os_free(identity);
1006
1007 policy = build_policy(ctx, user, realm, dmacc);
1008 if (!policy) {
1009 return build_post_dev_data_response(
1010 ctx, NULL, session_id,
1011 "No update available at this time", NULL);
1012 }
1013
1014 db_add_session(ctx, user, realm, session_id, NULL, NULL, POLICY_UPDATE);
1015
1016 status = "Update complete, request sppUpdateResponse";
1017 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1018 NULL);
1019 if (spp_node == NULL)
1020 return NULL;
1021
1022 snprintf(buf, sizeof(buf),
1023 "./Wi-Fi/%s/PerProviderSubscription/Credential1/Policy",
1024 realm);
1025
1026 if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
1027 xml_node_free(ctx->xml, spp_node);
1028 xml_node_free(ctx->xml, policy);
1029 return NULL;
1030 }
1031
1032 hs20_eventlog_node(ctx, user, realm, session_id, "policy update",
1033 policy);
1034 xml_node_free(ctx->xml, policy);
1035
1036 return spp_node;
1037}
1038
1039
1040static xml_node_t * spp_get_mo(struct hs20_svc *ctx, xml_node_t *node,
1041 const char *urn, int *valid, char **ret_err)
1042{
1043 xml_node_t *child, *tnds, *mo;
1044 const char *name;
1045 char *mo_urn;
1046 char *str;
1047 char fname[200];
1048
1049 *valid = -1;
1050 if (ret_err)
1051 *ret_err = NULL;
1052
1053 xml_node_for_each_child(ctx->xml, child, node) {
1054 xml_node_for_each_check(ctx->xml, child);
1055 name = xml_node_get_localname(ctx->xml, child);
1056 if (strcmp(name, "moContainer") != 0)
1057 continue;
1058 mo_urn = xml_node_get_attr_value_ns(ctx->xml, child, SPP_NS_URI,
1059 "moURN");
1060 if (strcasecmp(urn, mo_urn) == 0) {
1061 xml_node_get_attr_value_free(ctx->xml, mo_urn);
1062 break;
1063 }
1064 xml_node_get_attr_value_free(ctx->xml, mo_urn);
1065 }
1066
1067 if (child == NULL)
1068 return NULL;
1069
1070 debug_print(ctx, 1, "moContainer text for %s", urn);
1071 debug_dump_node(ctx, "moContainer", child);
1072
1073 str = xml_node_get_text(ctx->xml, child);
1074 debug_print(ctx, 1, "moContainer payload: '%s'", str);
1075 tnds = xml_node_from_buf(ctx->xml, str);
1076 xml_node_get_text_free(ctx->xml, str);
1077 if (tnds == NULL) {
1078 debug_print(ctx, 1, "could not parse moContainer text");
1079 return NULL;
1080 }
1081
1082 snprintf(fname, sizeof(fname), "%s/spp/dm_ddf-v1_2.dtd", ctx->root_dir);
1083 if (xml_validate_dtd(ctx->xml, tnds, fname, ret_err) == 0)
1084 *valid = 1;
1085 else if (ret_err && *ret_err &&
1086 os_strcmp(*ret_err, "No declaration for attribute xmlns of element MgmtTree\n") == 0) {
1087 free(*ret_err);
1088 debug_print(ctx, 1, "Ignore OMA-DM DDF DTD validation error for MgmtTree namespace declaration with xmlns attribute");
1089 *ret_err = NULL;
1090 *valid = 1;
1091 } else
1092 *valid = 0;
1093
1094 mo = tnds_to_mo(ctx->xml, tnds);
1095 xml_node_free(ctx->xml, tnds);
1096 if (mo == NULL) {
1097 debug_print(ctx, 1, "invalid moContainer for %s", urn);
1098 }
1099
1100 return mo;
1101}
1102
1103
1104static xml_node_t * spp_exec_upload_mo(struct hs20_svc *ctx,
1105 const char *session_id, const char *urn)
1106{
1107 xml_namespace_t *ns;
1108 xml_node_t *spp_node, *node, *exec_node;
1109
1110 spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
1111 NULL);
1112 if (spp_node == NULL)
1113 return NULL;
1114
1115 exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
1116
1117 node = xml_node_create(ctx->xml, exec_node, ns, "uploadMO");
1118 xml_node_add_attr(ctx->xml, node, ns, "moURN", urn);
1119
1120 return spp_node;
1121}
1122
1123
1124static xml_node_t * hs20_subscription_registration(struct hs20_svc *ctx,
1125 const char *realm,
1126 const char *session_id,
1127 const char *redirect_uri)
1128{
1129 xml_namespace_t *ns;
1130 xml_node_t *spp_node, *exec_node;
1131 char uri[300], *val;
1132
1133 if (db_add_session(ctx, NULL, realm, session_id, NULL, redirect_uri,
1134 SUBSCRIPTION_REGISTRATION) < 0)
1135 return NULL;
1136 val = db_get_osu_config_val(ctx, realm, "signup_url");
1137 if (val == NULL)
1138 return NULL;
1139
1140 spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
1141 NULL);
1142 if (spp_node == NULL)
1143 return NULL;
1144
1145 exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
1146
1147 snprintf(uri, sizeof(uri), "%s%s", val, session_id);
1148 os_free(val);
1149 xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI",
1150 uri);
1151 return spp_node;
1152}
1153
1154
1155static xml_node_t * hs20_user_input_remediation(struct hs20_svc *ctx,
1156 const char *user,
1157 const char *realm, int dmacc,
1158 const char *session_id)
1159{
1160 return build_sub_rem_resp(ctx, user, realm, session_id, 0, dmacc);
1161}
1162
1163
1164static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm,
1165 const char *field)
1166{
1167 char *cmd;
1168 struct get_db_field_data data;
1169
1170 cmd = sqlite3_mprintf("SELECT value FROM osu_config WHERE realm=%Q AND "
1171 "field=%Q", realm, field);
1172 if (cmd == NULL)
1173 return NULL;
1174 debug_print(ctx, 1, "DB: %s", cmd);
1175 memset(&data, 0, sizeof(data));
1176 data.field = "value";
1177 if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
1178 {
1179 debug_print(ctx, 1, "DB: Could not find osu_config %s: %s",
1180 realm, sqlite3_errmsg(ctx->db));
1181 sqlite3_free(cmd);
1182 return NULL;
1183 }
1184 sqlite3_free(cmd);
1185
1186 debug_print(ctx, 1, "DB: return '%s'", data.value);
1187 return data.value;
1188}
1189
1190
1191static xml_node_t * build_pps(struct hs20_svc *ctx,
1192 const char *user, const char *realm,
1193 const char *pw, const char *cert,
1194 int machine_managed)
1195{
1196 xml_node_t *pps, *c, *trust, *aaa, *aaa1, *upd, *homesp;
1197 xml_node_t *cred, *eap, *userpw;
1198
1199 pps = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
1200 "PerProviderSubscription");
1201 if (pps == NULL)
1202 return NULL;
1203
1204 add_text_node(ctx, pps, "UpdateIdentifier", "1");
1205
1206 c = xml_node_create(ctx->xml, pps, NULL, "Credential1");
1207
1208 add_text_node(ctx, c, "CredentialPriority", "1");
1209
1210 aaa = xml_node_create(ctx->xml, c, NULL, "AAAServerTrustRoot");
1211 aaa1 = xml_node_create(ctx->xml, aaa, NULL, "AAA1");
1212 add_text_node_conf(ctx, realm, aaa1, "CertURL",
1213 "aaa_trust_root_cert_url");
1214 add_text_node_conf(ctx, realm, aaa1, "CertSHA256Fingerprint",
1215 "aaa_trust_root_cert_fingerprint");
1216
1217 upd = xml_node_create(ctx->xml, c, NULL, "SubscriptionUpdate");
1218 add_text_node(ctx, upd, "UpdateInterval", "4294967295");
1219 add_text_node(ctx, upd, "UpdateMethod", "ClientInitiated");
1220 add_text_node(ctx, upd, "Restriction", "HomeSP");
1221 add_text_node_conf(ctx, realm, upd, "URI", "spp_http_auth_url");
1222 trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
1223 add_text_node_conf(ctx, realm, trust, "CertURL", "trust_root_cert_url");
1224 add_text_node_conf(ctx, realm, trust, "CertSHA256Fingerprint",
1225 "trust_root_cert_fingerprint");
1226
1227 homesp = xml_node_create(ctx->xml, c, NULL, "HomeSP");
1228 add_text_node_conf(ctx, realm, homesp, "FriendlyName", "friendly_name");
1229 add_text_node_conf(ctx, realm, homesp, "FQDN", "fqdn");
1230
1231 xml_node_create(ctx->xml, c, NULL, "SubscriptionParameters");
1232
1233 cred = xml_node_create(ctx->xml, c, NULL, "Credential");
1234 add_creation_date(ctx, cred);
1235 if (cert) {
1236 xml_node_t *dc;
1237 dc = xml_node_create(ctx->xml, cred, NULL,
1238 "DigitalCertificate");
1239 add_text_node(ctx, dc, "CertificateType", "x509v3");
1240 add_text_node(ctx, dc, "CertSHA256Fingerprint", cert);
1241 } else {
1242 userpw = build_username_password(ctx, cred, user, pw);
1243 add_text_node(ctx, userpw, "MachineManaged",
1244 machine_managed ? "TRUE" : "FALSE");
1245 eap = xml_node_create(ctx->xml, userpw, NULL, "EAPMethod");
1246 add_text_node(ctx, eap, "EAPType", "21");
1247 add_text_node(ctx, eap, "InnerMethod", "MS-CHAP-V2");
1248 }
1249 add_text_node(ctx, cred, "Realm", realm);
1250
1251 return pps;
1252}
1253
1254
1255static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx,
1256 const char *session_id,
1257 const char *user,
1258 const char *realm)
1259{
1260 xml_namespace_t *ns;
1261 xml_node_t *spp_node, *enroll, *exec_node;
1262 char *val;
1263 char password[11];
1264 char *b64;
1265
1266 if (new_password(password, sizeof(password)) < 0)
1267 return NULL;
1268
1269 spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
1270 NULL);
1271 if (spp_node == NULL)
1272 return NULL;
1273
1274 exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
1275
1276 enroll = xml_node_create(ctx->xml, exec_node, ns, "getCertificate");
1277 xml_node_add_attr(ctx->xml, enroll, NULL, "enrollmentProtocol", "EST");
1278
1279 val = db_get_osu_config_val(ctx, realm, "est_url");
1280 xml_node_create_text(ctx->xml, enroll, ns, "enrollmentServerURI",
1281 val ? val : "");
1282 os_free(val);
1283 xml_node_create_text(ctx->xml, enroll, ns, "estUserID", user);
1284
1285 b64 = (char *) base64_encode((unsigned char *) password,
1286 strlen(password), NULL);
1287 if (b64 == NULL) {
1288 xml_node_free(ctx->xml, spp_node);
1289 return NULL;
1290 }
1291 xml_node_create_text(ctx->xml, enroll, ns, "estPassword", b64);
1292 free(b64);
1293
1294 db_update_session_password(ctx, user, realm, session_id, password);
1295
1296 return spp_node;
1297}
1298
1299
1300static xml_node_t * hs20_user_input_registration(struct hs20_svc *ctx,
1301 const char *session_id,
1302 int enrollment_done)
1303{
1304 xml_namespace_t *ns;
1305 xml_node_t *spp_node, *node = NULL;
1306 xml_node_t *pps, *tnds;
1307 char buf[400];
1308 char *str;
1309 char *user, *realm, *pw, *type, *mm;
1310 const char *status;
1311 int cert = 0;
1312 int machine_managed = 0;
1313 char *fingerprint;
1314
1315 user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
1316 realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
1317 pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
1318
1319 if (!user || !realm || !pw) {
1320 debug_print(ctx, 1, "Could not find session info from DB for "
1321 "the new subscription");
1322 free(user);
1323 free(realm);
1324 free(pw);
1325 return NULL;
1326 }
1327
1328 mm = db_get_session_val(ctx, NULL, NULL, session_id, "machine_managed");
1329 if (mm && atoi(mm))
1330 machine_managed = 1;
1331 free(mm);
1332
1333 type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
1334 if (type && strcmp(type, "cert") == 0)
1335 cert = 1;
1336 free(type);
1337
1338 if (cert && !enrollment_done) {
1339 xml_node_t *ret;
1340 hs20_eventlog(ctx, user, realm, session_id,
1341 "request client certificate enrollment", NULL);
1342 ret = spp_exec_get_certificate(ctx, session_id, user, realm);
1343 free(user);
1344 free(realm);
1345 free(pw);
1346 return ret;
1347 }
1348
1349 if (!cert && strlen(pw) == 0) {
1350 machine_managed = 1;
1351 free(pw);
1352 pw = malloc(11);
1353 if (pw == NULL || new_password(pw, 11) < 0) {
1354 free(user);
1355 free(realm);
1356 free(pw);
1357 return NULL;
1358 }
1359 }
1360
1361 status = "Provisioning complete, request sppUpdateResponse";
1362 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1363 NULL);
1364 if (spp_node == NULL)
1365 return NULL;
1366
1367 fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
1368 pps = build_pps(ctx, user, realm, pw,
1369 fingerprint ? fingerprint : NULL, machine_managed);
1370 free(fingerprint);
1371 if (!pps) {
1372 xml_node_free(ctx->xml, spp_node);
1373 free(user);
1374 free(realm);
1375 free(pw);
1376 return NULL;
1377 }
1378
1379 debug_print(ctx, 1, "Request DB subscription registration on success "
1380 "notification");
1381 db_add_session_pps(ctx, user, realm, session_id, pps);
1382
1383 hs20_eventlog_node(ctx, user, realm, session_id,
1384 "new subscription", pps);
1385 free(user);
1386 free(pw);
1387
1388 tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL);
1389 xml_node_free(ctx->xml, pps);
1390 if (!tnds) {
1391 xml_node_free(ctx->xml, spp_node);
1392 free(realm);
1393 return NULL;
1394 }
1395
1396 str = xml_node_to_str(ctx->xml, tnds);
1397 xml_node_free(ctx->xml, tnds);
1398 if (str == NULL) {
1399 xml_node_free(ctx->xml, spp_node);
1400 free(realm);
1401 return NULL;
1402 }
1403
1404 node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str);
1405 free(str);
1406 snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm);
1407 free(realm);
1408 xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf);
1409 xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS);
1410
1411 return spp_node;
1412}
1413
1414
1415static xml_node_t * hs20_user_input_free_remediation(struct hs20_svc *ctx,
1416 const char *user,
1417 const char *realm,
1418 const char *session_id)
1419{
1420 xml_namespace_t *ns;
1421 xml_node_t *spp_node;
1422 xml_node_t *cred;
1423 char buf[400];
1424 char *status;
1425 char *free_account, *pw;
1426
1427 free_account = db_get_osu_config_val(ctx, realm, "free_account");
1428 if (free_account == NULL)
1429 return NULL;
1430 pw = db_get_val(ctx, free_account, realm, "password", 0);
1431 if (pw == NULL) {
1432 free(free_account);
1433 return NULL;
1434 }
1435
1436 cred = build_credential_pw(ctx, free_account, realm, pw);
1437 free(free_account);
1438 free(pw);
1439 if (!cred) {
1440 xml_node_free(ctx->xml, cred);
1441 return NULL;
1442 }
1443
1444 status = "Remediation complete, request sppUpdateResponse";
1445 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1446 NULL);
1447 if (spp_node == NULL)
1448 return NULL;
1449
1450 snprintf(buf, sizeof(buf),
1451 "./Wi-Fi/%s/PerProviderSubscription/Credential1/Credential",
1452 realm);
1453
1454 if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
1455 xml_node_free(ctx->xml, spp_node);
1456 return NULL;
1457 }
1458
1459 hs20_eventlog_node(ctx, user, realm, session_id,
1460 "free/public remediation", cred);
1461 xml_node_free(ctx->xml, cred);
1462
1463 return spp_node;
1464}
1465
1466
1467static xml_node_t * hs20_user_input_complete(struct hs20_svc *ctx,
1468 const char *user,
1469 const char *realm, int dmacc,
1470 const char *session_id)
1471{
1472 char *val;
1473 enum hs20_session_operation oper;
1474
1475 val = db_get_session_val(ctx, user, realm, session_id, "operation");
1476 if (val == NULL) {
1477 debug_print(ctx, 1, "No session %s found to continue",
1478 session_id);
1479 return NULL;
1480 }
1481 oper = atoi(val);
1482 free(val);
1483
1484 if (oper == USER_REMEDIATION) {
1485 return hs20_user_input_remediation(ctx, user, realm, dmacc,
1486 session_id);
1487 }
1488
1489 if (oper == FREE_REMEDIATION) {
1490 return hs20_user_input_free_remediation(ctx, user, realm,
1491 session_id);
1492 }
1493
1494 if (oper == SUBSCRIPTION_REGISTRATION) {
1495 return hs20_user_input_registration(ctx, session_id, 0);
1496 }
1497
1498 debug_print(ctx, 1, "User session %s not in state for user input "
1499 "completion", session_id);
1500 return NULL;
1501}
1502
1503
1504static xml_node_t * hs20_cert_enroll_completed(struct hs20_svc *ctx,
1505 const char *user,
1506 const char *realm, int dmacc,
1507 const char *session_id)
1508{
1509 char *val;
1510 enum hs20_session_operation oper;
1511
1512 val = db_get_session_val(ctx, user, realm, session_id, "operation");
1513 if (val == NULL) {
1514 debug_print(ctx, 1, "No session %s found to continue",
1515 session_id);
1516 return NULL;
1517 }
1518 oper = atoi(val);
1519 free(val);
1520
1521 if (oper == SUBSCRIPTION_REGISTRATION)
1522 return hs20_user_input_registration(ctx, session_id, 1);
1523
1524 debug_print(ctx, 1, "User session %s not in state for certificate "
1525 "enrollment completion", session_id);
1526 return NULL;
1527}
1528
1529
1530static xml_node_t * hs20_cert_enroll_failed(struct hs20_svc *ctx,
1531 const char *user,
1532 const char *realm, int dmacc,
1533 const char *session_id)
1534{
1535 char *val;
1536 enum hs20_session_operation oper;
1537 xml_node_t *spp_node, *node;
1538 char *status;
1539 xml_namespace_t *ns;
1540
1541 val = db_get_session_val(ctx, user, realm, session_id, "operation");
1542 if (val == NULL) {
1543 debug_print(ctx, 1, "No session %s found to continue",
1544 session_id);
1545 return NULL;
1546 }
1547 oper = atoi(val);
1548 free(val);
1549
1550 if (oper != SUBSCRIPTION_REGISTRATION) {
1551 debug_print(ctx, 1, "User session %s not in state for "
1552 "enrollment failure", session_id);
1553 return NULL;
1554 }
1555
1556 status = "Error occurred";
1557 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1558 NULL);
1559 if (spp_node == NULL)
1560 return NULL;
1561 node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
1562 xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
1563 "Credentials cannot be provisioned at this time");
1564 db_remove_session(ctx, user, realm, session_id);
1565
1566 return spp_node;
1567}
1568
1569
1570static xml_node_t * hs20_spp_post_dev_data(struct hs20_svc *ctx,
1571 xml_node_t *node,
1572 const char *user,
1573 const char *realm,
1574 const char *session_id,
1575 int dmacc)
1576{
1577 const char *req_reason;
1578 char *redirect_uri = NULL;
1579 char *req_reason_buf = NULL;
1580 char str[200];
1581 xml_node_t *ret = NULL, *devinfo = NULL, *devdetail = NULL;
1582 xml_node_t *mo;
1583 char *version;
1584 int valid;
1585 char *supp, *pos;
1586 char *err;
1587
1588 version = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
1589 "sppVersion");
1590 if (version == NULL || strstr(version, "1.0") == NULL) {
1591 ret = build_post_dev_data_response(
1592 ctx, NULL, session_id, "Error occurred",
1593 "SPP version not supported");
1594 hs20_eventlog_node(ctx, user, realm, session_id,
1595 "Unsupported sppVersion", ret);
1596 xml_node_get_attr_value_free(ctx->xml, version);
1597 return ret;
1598 }
1599 xml_node_get_attr_value_free(ctx->xml, version);
1600
1601 mo = get_node(ctx->xml, node, "supportedMOList");
1602 if (mo == NULL) {
1603 ret = build_post_dev_data_response(
1604 ctx, NULL, session_id, "Error occurred",
1605 "Other");
1606 hs20_eventlog_node(ctx, user, realm, session_id,
1607 "No supportedMOList element", ret);
1608 return ret;
1609 }
1610 supp = xml_node_get_text(ctx->xml, mo);
1611 for (pos = supp; pos && *pos; pos++)
1612 *pos = tolower(*pos);
1613 if (supp == NULL ||
1614 strstr(supp, URN_OMA_DM_DEVINFO) == NULL ||
1615 strstr(supp, URN_OMA_DM_DEVDETAIL) == NULL ||
1616 strstr(supp, URN_HS20_PPS) == NULL) {
1617 xml_node_get_text_free(ctx->xml, supp);
1618 ret = build_post_dev_data_response(
1619 ctx, NULL, session_id, "Error occurred",
1620 "One or more mandatory MOs not supported");
1621 hs20_eventlog_node(ctx, user, realm, session_id,
1622 "Unsupported MOs", ret);
1623 return ret;
1624 }
1625 xml_node_get_text_free(ctx->xml, supp);
1626
1627 req_reason_buf = xml_node_get_attr_value(ctx->xml, node,
1628 "requestReason");
1629 if (req_reason_buf == NULL) {
1630 debug_print(ctx, 1, "No requestReason attribute");
1631 return NULL;
1632 }
1633 req_reason = req_reason_buf;
1634
1635 redirect_uri = xml_node_get_attr_value(ctx->xml, node, "redirectURI");
1636
1637 debug_print(ctx, 1, "requestReason: %s sessionID: %s redirectURI: %s",
1638 req_reason, session_id, redirect_uri);
1639 snprintf(str, sizeof(str), "sppPostDevData: requestReason=%s",
1640 req_reason);
1641 hs20_eventlog(ctx, user, realm, session_id, str, NULL);
1642
1643 devinfo = spp_get_mo(ctx, node, URN_OMA_DM_DEVINFO, &valid, &err);
1644 if (devinfo == NULL) {
1645 ret = build_post_dev_data_response(ctx, NULL, session_id,
1646 "Error occurred", "Other");
1647 hs20_eventlog_node(ctx, user, realm, session_id,
1648 "No DevInfo moContainer in sppPostDevData",
1649 ret);
1650 os_free(err);
1651 goto out;
1652 }
1653
1654 hs20_eventlog_node(ctx, user, realm, session_id,
1655 "Received DevInfo MO", devinfo);
1656 if (valid == 0) {
1657 hs20_eventlog(ctx, user, realm, session_id,
1658 "OMA-DM DDF DTD validation errors in DevInfo MO",
1659 err);
1660 ret = build_post_dev_data_response(ctx, NULL, session_id,
1661 "Error occurred", "Other");
1662 os_free(err);
1663 goto out;
1664 }
1665 os_free(err);
1666 if (user)
1667 db_update_mo(ctx, user, realm, "devinfo", devinfo);
1668
1669 devdetail = spp_get_mo(ctx, node, URN_OMA_DM_DEVDETAIL, &valid, &err);
1670 if (devdetail == NULL) {
1671 ret = build_post_dev_data_response(ctx, NULL, session_id,
1672 "Error occurred", "Other");
1673 hs20_eventlog_node(ctx, user, realm, session_id,
1674 "No DevDetail moContainer in sppPostDevData",
1675 ret);
1676 os_free(err);
1677 goto out;
1678 }
1679
1680 hs20_eventlog_node(ctx, user, realm, session_id,
1681 "Received DevDetail MO", devdetail);
1682 if (valid == 0) {
1683 hs20_eventlog(ctx, user, realm, session_id,
1684 "OMA-DM DDF DTD validation errors "
1685 "in DevDetail MO", err);
1686 ret = build_post_dev_data_response(ctx, NULL, session_id,
1687 "Error occurred", "Other");
1688 os_free(err);
1689 goto out;
1690 }
1691 os_free(err);
1692 if (user)
1693 db_update_mo(ctx, user, realm, "devdetail", devdetail);
1694
1695 if (user)
1696 mo = spp_get_mo(ctx, node, URN_HS20_PPS, &valid, &err);
1697 else {
1698 mo = NULL;
1699 err = NULL;
1700 }
1701 if (user && mo) {
1702 hs20_eventlog_node(ctx, user, realm, session_id,
1703 "Received PPS MO", mo);
1704 if (valid == 0) {
1705 hs20_eventlog(ctx, user, realm, session_id,
1706 "OMA-DM DDF DTD validation errors "
1707 "in PPS MO", err);
1708 xml_node_get_attr_value_free(ctx->xml, redirect_uri);
1709 os_free(err);
1710 return build_post_dev_data_response(
1711 ctx, NULL, session_id,
1712 "Error occurred", "Other");
1713 }
1714 db_update_mo(ctx, user, realm, "pps", mo);
1715 db_update_val(ctx, user, realm, "fetch_pps", "0", dmacc);
1716 xml_node_free(ctx->xml, mo);
1717 }
1718 os_free(err);
1719
1720 if (user && !mo) {
1721 char *fetch;
1722 int fetch_pps;
1723
1724 fetch = db_get_val(ctx, user, realm, "fetch_pps", dmacc);
1725 fetch_pps = fetch ? atoi(fetch) : 0;
1726 free(fetch);
1727
1728 if (fetch_pps) {
1729 enum hs20_session_operation oper;
1730 if (strcasecmp(req_reason, "Subscription remediation")
1731 == 0)
1732 oper = CONTINUE_SUBSCRIPTION_REMEDIATION;
1733 else if (strcasecmp(req_reason, "Policy update") == 0)
1734 oper = CONTINUE_POLICY_UPDATE;
1735 else
1736 oper = NO_OPERATION;
1737 if (db_add_session(ctx, user, realm, session_id, NULL,
1738 NULL, oper) < 0)
1739 goto out;
1740
1741 ret = spp_exec_upload_mo(ctx, session_id,
1742 URN_HS20_PPS);
1743 hs20_eventlog_node(ctx, user, realm, session_id,
1744 "request PPS MO upload",
1745 ret);
1746 goto out;
1747 }
1748 }
1749
1750 if (user && strcasecmp(req_reason, "MO upload") == 0) {
1751 char *val = db_get_session_val(ctx, user, realm, session_id,
1752 "operation");
1753 enum hs20_session_operation oper;
1754 if (!val) {
1755 debug_print(ctx, 1, "No session %s found to continue",
1756 session_id);
1757 goto out;
1758 }
1759 oper = atoi(val);
1760 free(val);
1761 if (oper == CONTINUE_SUBSCRIPTION_REMEDIATION)
1762 req_reason = "Subscription remediation";
1763 else if (oper == CONTINUE_POLICY_UPDATE)
1764 req_reason = "Policy update";
1765 else {
1766 debug_print(ctx, 1,
1767 "No pending operation in session %s",
1768 session_id);
1769 goto out;
1770 }
1771 }
1772
1773 if (strcasecmp(req_reason, "Subscription registration") == 0) {
1774 ret = hs20_subscription_registration(ctx, realm, session_id,
1775 redirect_uri);
1776 hs20_eventlog_node(ctx, user, realm, session_id,
1777 "subscription registration response",
1778 ret);
1779 goto out;
1780 }
1781 if (user && strcasecmp(req_reason, "Subscription remediation") == 0) {
1782 ret = hs20_subscription_remediation(ctx, user, realm,
1783 session_id, dmacc,
1784 redirect_uri);
1785 hs20_eventlog_node(ctx, user, realm, session_id,
1786 "subscription remediation response",
1787 ret);
1788 goto out;
1789 }
1790 if (user && strcasecmp(req_reason, "Policy update") == 0) {
1791 ret = hs20_policy_update(ctx, user, realm, session_id, dmacc);
1792 hs20_eventlog_node(ctx, user, realm, session_id,
1793 "policy update response",
1794 ret);
1795 goto out;
1796 }
1797
1798 if (strcasecmp(req_reason, "User input completed") == 0) {
1799 if (devinfo)
1800 db_add_session_devinfo(ctx, session_id, devinfo);
1801 if (devdetail)
1802 db_add_session_devdetail(ctx, session_id, devdetail);
1803 ret = hs20_user_input_complete(ctx, user, realm, dmacc,
1804 session_id);
1805 hs20_eventlog_node(ctx, user, realm, session_id,
1806 "user input completed response", ret);
1807 goto out;
1808 }
1809
1810 if (strcasecmp(req_reason, "Certificate enrollment completed") == 0) {
1811 ret = hs20_cert_enroll_completed(ctx, user, realm, dmacc,
1812 session_id);
1813 hs20_eventlog_node(ctx, user, realm, session_id,
1814 "certificate enrollment response", ret);
1815 goto out;
1816 }
1817
1818 if (strcasecmp(req_reason, "Certificate enrollment failed") == 0) {
1819 ret = hs20_cert_enroll_failed(ctx, user, realm, dmacc,
1820 session_id);
1821 hs20_eventlog_node(ctx, user, realm, session_id,
1822 "certificate enrollment failed response",
1823 ret);
1824 goto out;
1825 }
1826
1827 debug_print(ctx, 1, "Unsupported requestReason '%s' user '%s'",
1828 req_reason, user);
1829out:
1830 xml_node_get_attr_value_free(ctx->xml, req_reason_buf);
1831 xml_node_get_attr_value_free(ctx->xml, redirect_uri);
1832 if (devinfo)
1833 xml_node_free(ctx->xml, devinfo);
1834 if (devdetail)
1835 xml_node_free(ctx->xml, devdetail);
1836 return ret;
1837}
1838
1839
1840static xml_node_t * build_spp_exchange_complete(struct hs20_svc *ctx,
1841 const char *session_id,
1842 const char *status,
1843 const char *error_code)
1844{
1845 xml_namespace_t *ns;
1846 xml_node_t *spp_node, *node;
1847
1848 spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
1849 "sppExchangeComplete");
1850
1851
1852 xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
1853 xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
1854 xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
1855
1856 if (error_code) {
1857 node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
1858 xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
1859 error_code);
1860 }
1861
1862 return spp_node;
1863}
1864
1865
1866static int add_subscription(struct hs20_svc *ctx, const char *session_id)
1867{
1868 char *user, *realm, *pw, *pw_mm, *pps, *str;
1869 char *sql;
1870 int ret = -1;
1871 char *free_account;
1872 int free_acc;
1873 char *type;
1874 int cert = 0;
1875 char *cert_pem, *fingerprint;
1876
1877 user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
1878 realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
1879 pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
1880 pw_mm = db_get_session_val(ctx, NULL, NULL, session_id,
1881 "machine_managed");
1882 pps = db_get_session_val(ctx, NULL, NULL, session_id, "pps");
1883 cert_pem = db_get_session_val(ctx, NULL, NULL, session_id, "cert_pem");
1884 fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
1885 type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
1886 if (type && strcmp(type, "cert") == 0)
1887 cert = 1;
1888 free(type);
1889
1890 if (!user || !realm || !pw) {
1891 debug_print(ctx, 1, "Could not find session info from DB for "
1892 "the new subscription");
1893 goto out;
1894 }
1895
1896 free_account = db_get_osu_config_val(ctx, realm, "free_account");
1897 free_acc = free_account && strcmp(free_account, user) == 0;
1898 free(free_account);
1899
1900 debug_print(ctx, 1,
1901 "New subscription: user='%s' realm='%s' free_acc=%d",
1902 user, realm, free_acc);
1903 debug_print(ctx, 1, "New subscription: pps='%s'", pps);
1904
1905 sql = sqlite3_mprintf("UPDATE eventlog SET user=%Q, realm=%Q WHERE "
1906 "sessionid=%Q AND (user='' OR user IS NULL)",
1907 user, realm, session_id);
1908 if (sql) {
1909 debug_print(ctx, 1, "DB: %s", sql);
1910 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
1911 debug_print(ctx, 1, "Failed to update eventlog in "
1912 "sqlite database: %s",
1913 sqlite3_errmsg(ctx->db));
1914 }
1915 sqlite3_free(sql);
1916 }
1917
1918 if (free_acc) {
1919 hs20_eventlog(ctx, user, realm, session_id,
1920 "completed shared free account registration",
1921 NULL);
1922 ret = 0;
1923 goto out;
1924 }
1925
1926 sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,"
1927 "methods,cert,cert_pem,machine_managed) VALUES "
1928 "(%Q,%Q,1,%Q,%Q,%Q,%d)",
1929 user, realm, cert ? "TLS" : "TTLS-MSCHAPV2",
1930 fingerprint ? fingerprint : "",
1931 cert_pem ? cert_pem : "",
1932 pw_mm && atoi(pw_mm) ? 1 : 0);
1933 if (sql == NULL)
1934 goto out;
1935 debug_print(ctx, 1, "DB: %s", sql);
1936 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
1937 debug_print(ctx, 1, "Failed to add user in sqlite database: %s",
1938 sqlite3_errmsg(ctx->db));
1939 sqlite3_free(sql);
1940 goto out;
1941 }
1942 sqlite3_free(sql);
1943
1944 if (cert)
1945 ret = 0;
1946 else
1947 ret = update_password(ctx, user, realm, pw, 0);
1948 if (ret < 0) {
1949 sql = sqlite3_mprintf("DELETE FROM users WHERE identity=%Q AND "
1950 "realm=%Q AND phase2=1",
1951 user, realm);
1952 if (sql) {
1953 debug_print(ctx, 1, "DB: %s", sql);
1954 sqlite3_exec(ctx->db, sql, NULL, NULL, NULL);
1955 sqlite3_free(sql);
1956 }
1957 }
1958
1959 if (pps)
1960 db_update_mo_str(ctx, user, realm, "pps", pps);
1961
1962 str = db_get_session_val(ctx, NULL, NULL, session_id, "devinfo");
1963 if (str) {
1964 db_update_mo_str(ctx, user, realm, "devinfo", str);
1965 free(str);
1966 }
1967
1968 str = db_get_session_val(ctx, NULL, NULL, session_id, "devdetail");
1969 if (str) {
1970 db_update_mo_str(ctx, user, realm, "devdetail", str);
1971 free(str);
1972 }
1973
1974 if (ret == 0) {
1975 hs20_eventlog(ctx, user, realm, session_id,
1976 "completed subscription registration", NULL);
1977 }
1978
1979out:
1980 free(user);
1981 free(realm);
1982 free(pw);
1983 free(pw_mm);
1984 free(pps);
1985 free(cert_pem);
1986 free(fingerprint);
1987 return ret;
1988}
1989
1990
1991static xml_node_t * hs20_spp_update_response(struct hs20_svc *ctx,
1992 xml_node_t *node,
1993 const char *user,
1994 const char *realm,
1995 const char *session_id,
1996 int dmacc)
1997{
1998 char *status;
1999 xml_node_t *ret;
2000 char *val;
2001 enum hs20_session_operation oper;
2002
2003 status = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
2004 "sppStatus");
2005 if (status == NULL) {
2006 debug_print(ctx, 1, "No sppStatus attribute");
2007 return NULL;
2008 }
2009
2010 debug_print(ctx, 1, "sppUpdateResponse: sppStatus: %s sessionID: %s",
2011 status, session_id);
2012
2013 val = db_get_session_val(ctx, user, realm, session_id, "operation");
2014 if (!val) {
2015 debug_print(ctx, 1,
2016 "No session active for user: %s sessionID: %s",
2017 user, session_id);
2018 oper = NO_OPERATION;
2019 } else
2020 oper = atoi(val);
2021
2022 if (strcasecmp(status, "OK") == 0) {
2023 char *new_pw = NULL;
2024
2025 xml_node_get_attr_value_free(ctx->xml, status);
2026
2027 if (oper == USER_REMEDIATION) {
2028 new_pw = db_get_session_val(ctx, user, realm,
2029 session_id, "password");
2030 if (new_pw == NULL || strlen(new_pw) == 0) {
2031 free(new_pw);
2032 ret = build_spp_exchange_complete(
2033 ctx, session_id, "Error occurred",
2034 "Other");
2035 hs20_eventlog_node(ctx, user, realm,
2036 session_id, "No password "
2037 "had been assigned for "
2038 "session", ret);
2039 db_remove_session(ctx, user, realm, session_id);
2040 return ret;
2041 }
2042 oper = UPDATE_PASSWORD;
2043 }
2044 if (oper == UPDATE_PASSWORD) {
2045 if (!new_pw) {
2046 new_pw = db_get_session_val(ctx, user, realm,
2047 session_id,
2048 "password");
2049 if (!new_pw) {
2050 db_remove_session(ctx, user, realm,
2051 session_id);
2052 return NULL;
2053 }
2054 }
2055 debug_print(ctx, 1, "Update user '%s' password in DB",
2056 user);
2057 if (update_password(ctx, user, realm, new_pw, dmacc) <
2058 0) {
2059 debug_print(ctx, 1, "Failed to update user "
2060 "'%s' password in DB", user);
2061 ret = build_spp_exchange_complete(
2062 ctx, session_id, "Error occurred",
2063 "Other");
2064 hs20_eventlog_node(ctx, user, realm,
2065 session_id, "Failed to "
2066 "update database", ret);
2067 db_remove_session(ctx, user, realm, session_id);
2068 return ret;
2069 }
2070 hs20_eventlog(ctx, user, realm,
2071 session_id, "Updated user password "
2072 "in database", NULL);
2073 }
2074 if (oper == SUBSCRIPTION_REGISTRATION) {
2075 if (add_subscription(ctx, session_id) < 0) {
2076 debug_print(ctx, 1, "Failed to add "
2077 "subscription into DB");
2078 ret = build_spp_exchange_complete(
2079 ctx, session_id, "Error occurred",
2080 "Other");
2081 hs20_eventlog_node(ctx, user, realm,
2082 session_id, "Failed to "
2083 "update database", ret);
2084 db_remove_session(ctx, user, realm, session_id);
2085 return ret;
2086 }
2087 }
2088 if (oper == POLICY_REMEDIATION || oper == POLICY_UPDATE) {
2089 char *val;
2090 val = db_get_val(ctx, user, realm, "remediation",
2091 dmacc);
2092 if (val && strcmp(val, "policy") == 0)
2093 db_update_val(ctx, user, realm, "remediation",
2094 "", dmacc);
2095 free(val);
2096 }
2097 ret = build_spp_exchange_complete(
2098 ctx, session_id,
2099 "Exchange complete, release TLS connection", NULL);
2100 hs20_eventlog_node(ctx, user, realm, session_id,
2101 "Exchange completed", ret);
2102 db_remove_session(ctx, user, realm, session_id);
2103 return ret;
2104 }
2105
2106 ret = build_spp_exchange_complete(ctx, session_id, "Error occurred",
2107 "Other");
2108 hs20_eventlog_node(ctx, user, realm, session_id, "Error occurred", ret);
2109 db_remove_session(ctx, user, realm, session_id);
2110 xml_node_get_attr_value_free(ctx->xml, status);
2111 return ret;
2112}
2113
2114
2115#define SPP_SESSION_ID_LEN 16
2116
2117static char * gen_spp_session_id(void)
2118{
2119 FILE *f;
2120 int i;
2121 char *session;
2122
2123 session = os_malloc(SPP_SESSION_ID_LEN * 2 + 1);
2124 if (session == NULL)
2125 return NULL;
2126
2127 f = fopen("/dev/urandom", "r");
2128 if (f == NULL) {
2129 os_free(session);
2130 return NULL;
2131 }
2132 for (i = 0; i < SPP_SESSION_ID_LEN; i++)
2133 os_snprintf(session + i * 2, 3, "%02x", fgetc(f));
2134
2135 fclose(f);
2136 return session;
2137}
2138
2139xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node,
2140 const char *auth_user,
2141 const char *auth_realm, int dmacc)
2142{
2143 xml_node_t *ret = NULL;
2144 char *session_id;
2145 const char *op_name;
2146 char *xml_err;
2147 char fname[200];
2148
2149 debug_dump_node(ctx, "received request", node);
2150
2151 if (!dmacc && auth_user && auth_realm) {
2152 char *real;
2153 real = db_get_val(ctx, auth_user, auth_realm, "identity", 0);
2154 if (!real) {
2155 real = db_get_val(ctx, auth_user, auth_realm,
2156 "identity", 1);
2157 if (real)
2158 dmacc = 1;
2159 }
2160 os_free(real);
2161 }
2162
2163 snprintf(fname, sizeof(fname), "%s/spp/spp.xsd", ctx->root_dir);
2164 if (xml_validate(ctx->xml, node, fname, &xml_err) < 0) {
2165 /*
2166 * We may not be able to extract the sessionID from invalid
2167 * input, but well, we can try.
2168 */
2169 session_id = xml_node_get_attr_value_ns(ctx->xml, node,
2170 SPP_NS_URI,
2171 "sessionID");
2172 debug_print(ctx, 1, "SPP message failed validation");
2173 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2174 "SPP message failed validation", node);
2175 hs20_eventlog(ctx, auth_user, auth_realm, session_id,
2176 "Validation errors", xml_err);
2177 os_free(xml_err);
2178 xml_node_get_attr_value_free(ctx->xml, session_id);
2179 /* TODO: what to return here? */
2180 ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2181 "SppValidationError");
2182 return ret;
2183 }
2184
2185 session_id = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
2186 "sessionID");
2187 if (session_id) {
2188 char *tmp;
2189 debug_print(ctx, 1, "Received sessionID %s", session_id);
2190 tmp = os_strdup(session_id);
2191 xml_node_get_attr_value_free(ctx->xml, session_id);
2192 if (tmp == NULL)
2193 return NULL;
2194 session_id = tmp;
2195 } else {
2196 session_id = gen_spp_session_id();
2197 if (session_id == NULL) {
2198 debug_print(ctx, 1, "Failed to generate sessionID");
2199 return NULL;
2200 }
2201 debug_print(ctx, 1, "Generated sessionID %s", session_id);
2202 }
2203
2204 op_name = xml_node_get_localname(ctx->xml, node);
2205 if (op_name == NULL) {
2206 debug_print(ctx, 1, "Could not get op_name");
2207 return NULL;
2208 }
2209
2210 if (strcmp(op_name, "sppPostDevData") == 0) {
2211 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2212 "sppPostDevData received and validated",
2213 node);
2214 ret = hs20_spp_post_dev_data(ctx, node, auth_user, auth_realm,
2215 session_id, dmacc);
2216 } else if (strcmp(op_name, "sppUpdateResponse") == 0) {
2217 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2218 "sppUpdateResponse received and validated",
2219 node);
2220 ret = hs20_spp_update_response(ctx, node, auth_user,
2221 auth_realm, session_id, dmacc);
2222 } else {
2223 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2224 "Unsupported SPP message received and "
2225 "validated", node);
2226 debug_print(ctx, 1, "Unsupported operation '%s'", op_name);
2227 /* TODO: what to return here? */
2228 ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2229 "SppUnknownCommandError");
2230 }
2231 os_free(session_id);
2232
2233 if (ret == NULL) {
2234 /* TODO: what to return here? */
2235 ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2236 "SppInternalError");
2237 }
2238
2239 return ret;
2240}
2241
2242
2243int hs20_spp_server_init(struct hs20_svc *ctx)
2244{
2245 char fname[200];
2246 ctx->db = NULL;
2247 snprintf(fname, sizeof(fname), "%s/AS/DB/eap_user.db", ctx->root_dir);
2248 if (sqlite3_open(fname, &ctx->db)) {
2249 printf("Failed to open sqlite database: %s\n",
2250 sqlite3_errmsg(ctx->db));
2251 sqlite3_close(ctx->db);
2252 return -1;
2253 }
2254
2255 return 0;
2256}
2257
2258
2259void hs20_spp_server_deinit(struct hs20_svc *ctx)
2260{
2261 sqlite3_close(ctx->db);
2262 ctx->db = NULL;
2263}