2 * Hotspot 2.0 SPP server
3 * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
20 #include "xml-utils.h"
21 #include "spp_server.h"
24 #define SPP_NS_URI "http://www.wi-fi.org/specifications/hotspot2dot0/v1.0/spp"
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"
32 /* TODO: timeout to expire sessions */
34 enum hs20_session_operation {
37 CONTINUE_SUBSCRIPTION_REMEDIATION,
38 CONTINUE_POLICY_UPDATE,
40 SUBSCRIPTION_REGISTRATION,
47 static char * db_get_session_val(struct hs20_svc *ctx, const char *user,
48 const char *realm, const char *session_id,
50 static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm,
52 static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
53 const char *realm, int use_dmacc);
56 static 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)
65 sql = sqlite3_mprintf("INSERT INTO sessions(timestamp,id,user,realm,"
66 "operation,password,redirect_uri) "
68 "(strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
70 sessionid, user ? user : "", realm ? realm : "",
71 operation, pw ? pw : "",
72 redirect_uri ? redirect_uri : "");
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));
86 static void db_update_session_password(struct hs20_svc *ctx, const char *user,
87 const char *realm, const char *sessionid,
92 sql = sqlite3_mprintf("UPDATE sessions SET password=%Q WHERE id=%Q AND "
93 "user=%Q AND realm=%Q",
94 pw, sessionid, user, realm);
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));
106 static void db_update_session_machine_managed(struct hs20_svc *ctx,
109 const char *sessionid,
114 sql = sqlite3_mprintf("UPDATE sessions SET machine_managed=%Q WHERE id=%Q AND user=%Q AND realm=%Q",
115 pw_mm ? "1" : "0", sessionid, user, realm);
118 debug_print(ctx, 1, "DB: %s", sql);
119 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
121 "Failed to update session machine_managed: %s",
122 sqlite3_errmsg(ctx->db));
128 static void db_add_session_pps(struct hs20_svc *ctx, const char *user,
129 const char *realm, const char *sessionid,
135 str = xml_node_to_str(ctx->xml, node);
138 sql = sqlite3_mprintf("UPDATE sessions SET pps=%Q WHERE id=%Q AND "
139 "user=%Q AND realm=%Q",
140 str, sessionid, user, realm);
144 debug_print(ctx, 1, "DB: %s", sql);
145 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
146 debug_print(ctx, 1, "Failed to add session pps: %s",
147 sqlite3_errmsg(ctx->db));
153 static void db_add_session_devinfo(struct hs20_svc *ctx, const char *sessionid,
159 str = xml_node_to_str(ctx->xml, node);
162 sql = sqlite3_mprintf("UPDATE sessions SET devinfo=%Q WHERE id=%Q",
167 debug_print(ctx, 1, "DB: %s", sql);
168 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
169 debug_print(ctx, 1, "Failed to add session devinfo: %s",
170 sqlite3_errmsg(ctx->db));
176 static void db_add_session_devdetail(struct hs20_svc *ctx,
177 const char *sessionid,
183 str = xml_node_to_str(ctx->xml, node);
186 sql = sqlite3_mprintf("UPDATE sessions SET devdetail=%Q WHERE id=%Q",
191 debug_print(ctx, 1, "DB: %s", sql);
192 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
193 debug_print(ctx, 1, "Failed to add session devdetail: %s",
194 sqlite3_errmsg(ctx->db));
200 static void db_remove_session(struct hs20_svc *ctx,
201 const char *user, const char *realm,
202 const char *sessionid)
206 if (user == NULL || realm == NULL) {
207 sql = sqlite3_mprintf("DELETE FROM sessions WHERE "
210 sql = sqlite3_mprintf("DELETE FROM sessions WHERE "
211 "user=%Q AND realm=%Q AND id=%Q",
212 user, realm, sessionid);
216 debug_print(ctx, 1, "DB: %s", sql);
217 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
218 debug_print(ctx, 1, "Failed to delete session entry from "
219 "sqlite database: %s", sqlite3_errmsg(ctx->db));
225 static void hs20_eventlog(struct hs20_svc *ctx,
226 const char *user, const char *realm,
227 const char *sessionid, const char *notes,
231 char *user_buf = NULL, *realm_buf = NULL;
233 debug_print(ctx, 1, "eventlog: %s", notes);
236 user_buf = db_get_session_val(ctx, NULL, NULL, sessionid,
239 realm_buf = db_get_session_val(ctx, NULL, NULL, sessionid,
244 sql = sqlite3_mprintf("INSERT INTO eventlog"
245 "(user,realm,sessionid,timestamp,notes,dump,addr)"
247 "strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
249 user, realm, sessionid, notes,
250 dump ? dump : "", ctx->addr ? ctx->addr : "");
255 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
256 debug_print(ctx, 1, "Failed to add eventlog entry into sqlite "
257 "database: %s", sqlite3_errmsg(ctx->db));
263 static void hs20_eventlog_node(struct hs20_svc *ctx,
264 const char *user, const char *realm,
265 const char *sessionid, const char *notes,
271 str = xml_node_to_str(ctx->xml, node);
274 hs20_eventlog(ctx, user, realm, sessionid, notes, str);
279 static void db_update_mo_str(struct hs20_svc *ctx, const char *user,
280 const char *realm, const char *name,
284 if (user == NULL || realm == NULL || name == NULL)
286 sql = sqlite3_mprintf("UPDATE users SET %s=%Q "
287 "WHERE identity=%Q AND realm=%Q AND phase2=1",
288 name, str, user, realm);
291 debug_print(ctx, 1, "DB: %s", sql);
292 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
293 debug_print(ctx, 1, "Failed to update user MO entry in sqlite "
294 "database: %s", sqlite3_errmsg(ctx->db));
300 static void db_update_mo(struct hs20_svc *ctx, const char *user,
301 const char *realm, const char *name, xml_node_t *mo)
305 str = xml_node_to_str(ctx->xml, mo);
309 db_update_mo_str(ctx, user, realm, name, str);
314 static void add_text_node(struct hs20_svc *ctx, xml_node_t *parent,
315 const char *name, const char *value)
317 xml_node_create_text(ctx->xml, parent, NULL, name, value ? value : "");
321 static void add_text_node_conf(struct hs20_svc *ctx, const char *realm,
322 xml_node_t *parent, const char *name,
326 val = db_get_osu_config_val(ctx, realm, field);
327 xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : "");
332 static int new_password(char *buf, int buflen)
338 buf[buflen - 1] = '\0';
339 if (os_get_random((unsigned char *) buf, buflen - 1) < 0)
342 for (i = 0; i < buflen - 1; i++) {
343 unsigned char val = buf[i];
347 else if (val < 2 * 26)
348 buf[i] = 'A' + val - 26;
350 buf[i] = '0' + val - 2 * 26;
357 struct get_db_field_data {
363 static int get_db_field(void *ctx, int argc, char *argv[], char *col[])
365 struct get_db_field_data *data = ctx;
368 for (i = 0; i < argc; i++) {
369 if (os_strcmp(col[i], data->field) == 0 && argv[i]) {
370 os_free(data->value);
371 data->value = os_strdup(argv[i]);
380 static char * db_get_val(struct hs20_svc *ctx, const char *user,
381 const char *realm, const char *field, int dmacc)
384 struct get_db_field_data data;
386 cmd = sqlite3_mprintf("SELECT %s FROM users WHERE "
387 "%s=%Q AND realm=%Q AND phase2=1",
388 field, dmacc ? "osu_user" : "identity",
392 memset(&data, 0, sizeof(data));
394 if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
396 debug_print(ctx, 1, "Could not find user '%s'", user);
402 debug_print(ctx, 1, "DB: user='%s' realm='%s' field='%s' dmacc=%d --> "
403 "value='%s'", user, realm, field, dmacc, data.value);
409 static int db_update_val(struct hs20_svc *ctx, const char *user,
410 const char *realm, const char *field,
411 const char *val, int dmacc)
416 cmd = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE "
417 "%s=%Q AND realm=%Q AND phase2=1",
418 field, val, dmacc ? "osu_user" : "identity", user,
422 debug_print(ctx, 1, "DB: %s", cmd);
423 if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
425 "Failed to update user in sqlite database: %s",
426 sqlite3_errmsg(ctx->db));
430 "DB: user='%s' realm='%s' field='%s' set to '%s'",
431 user, realm, field, val);
440 static char * db_get_session_val(struct hs20_svc *ctx, const char *user,
441 const char *realm, const char *session_id,
445 struct get_db_field_data data;
447 if (user == NULL || realm == NULL) {
448 cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE "
449 "id=%Q", field, session_id);
451 cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE "
452 "user=%Q AND realm=%Q AND id=%Q",
453 field, user, realm, session_id);
457 debug_print(ctx, 1, "DB: %s", cmd);
458 memset(&data, 0, sizeof(data));
460 if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
462 debug_print(ctx, 1, "DB: Could not find session %s: %s",
463 session_id, sqlite3_errmsg(ctx->db));
469 debug_print(ctx, 1, "DB: return '%s'", data.value);
474 static int update_password(struct hs20_svc *ctx, const char *user,
475 const char *realm, const char *pw, int dmacc)
479 cmd = sqlite3_mprintf("UPDATE users SET password=%Q, "
481 "WHERE %s=%Q AND phase2=1",
482 pw, dmacc ? "osu_user" : "identity",
486 debug_print(ctx, 1, "DB: %s", cmd);
487 if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
488 debug_print(ctx, 1, "Failed to update database for user '%s'",
497 static int add_eap_ttls(struct hs20_svc *ctx, xml_node_t *parent)
501 node = xml_node_create(ctx->xml, parent, NULL, "EAPMethod");
505 add_text_node(ctx, node, "EAPType", "21");
506 add_text_node(ctx, node, "InnerMethod", "MS-CHAP-V2");
512 static xml_node_t * build_username_password(struct hs20_svc *ctx,
514 const char *user, const char *pw)
519 node = xml_node_create(ctx->xml, parent, NULL, "UsernamePassword");
523 add_text_node(ctx, node, "Username", user);
525 b64 = (char *) base64_encode((unsigned char *) pw, strlen(pw), NULL);
528 add_text_node(ctx, node, "Password", b64);
535 static int add_username_password(struct hs20_svc *ctx, xml_node_t *cred,
536 const char *user, const char *pw)
540 node = build_username_password(ctx, cred, user, pw);
544 add_text_node(ctx, node, "MachineManaged", "TRUE");
545 add_text_node(ctx, node, "SoftTokenApp", "");
546 add_eap_ttls(ctx, node);
552 static void add_creation_date(struct hs20_svc *ctx, xml_node_t *cred)
560 snprintf(str, sizeof(str), "%04u-%02u-%02uT%02u:%02u:%02uZ",
561 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
562 tm.tm_hour, tm.tm_min, tm.tm_sec);
563 xml_node_create_text(ctx->xml, cred, NULL, "CreationDate", str);
567 static xml_node_t * build_credential_pw(struct hs20_svc *ctx,
568 const char *user, const char *realm,
573 cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential");
575 debug_print(ctx, 1, "Failed to create Credential node");
578 add_creation_date(ctx, cred);
579 if (add_username_password(ctx, cred, user, pw) < 0) {
580 xml_node_free(ctx->xml, cred);
583 add_text_node(ctx, cred, "Realm", realm);
589 static xml_node_t * build_credential(struct hs20_svc *ctx,
590 const char *user, const char *realm,
591 char *new_pw, size_t new_pw_len)
593 if (new_password(new_pw, new_pw_len) < 0)
595 debug_print(ctx, 1, "Update password to '%s'", new_pw);
596 return build_credential_pw(ctx, user, realm, new_pw);
600 static xml_node_t * build_credential_cert(struct hs20_svc *ctx,
601 const char *user, const char *realm,
602 const char *cert_fingerprint)
604 xml_node_t *cred, *cert;
606 cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential");
608 debug_print(ctx, 1, "Failed to create Credential node");
611 add_creation_date(ctx, cred);
612 cert = xml_node_create(ctx->xml, cred, NULL, "DigitalCertificate");
613 add_text_node(ctx, cert, "CertificateType", "x509v3");
614 add_text_node(ctx, cert, "CertSHA256Fingerprint", cert_fingerprint);
615 add_text_node(ctx, cred, "Realm", realm);
621 static xml_node_t * build_post_dev_data_response(struct hs20_svc *ctx,
622 xml_namespace_t **ret_ns,
623 const char *session_id,
625 const char *error_code)
627 xml_node_t *spp_node = NULL;
630 spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
631 "sppPostDevDataResponse");
632 if (spp_node == NULL)
637 xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
638 xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
639 xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
643 node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
645 xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
653 static int add_update_node(struct hs20_svc *ctx, xml_node_t *spp_node,
654 xml_namespace_t *ns, const char *uri,
655 xml_node_t *upd_node)
657 xml_node_t *node, *tnds;
660 tnds = mo_to_tnds(ctx->xml, upd_node, 0, NULL, NULL);
664 str = xml_node_to_str(ctx->xml, tnds);
665 xml_node_free(ctx->xml, tnds);
668 node = xml_node_create_text(ctx->xml, spp_node, ns, "updateNode", str);
671 xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", uri);
677 static xml_node_t * build_sub_rem_resp(struct hs20_svc *ctx,
678 const char *user, const char *realm,
679 const char *session_id,
680 int machine_rem, int dmacc)
683 xml_node_t *spp_node, *cred;
686 char *real_user = NULL;
691 real_user = db_get_val(ctx, user, realm, "identity", dmacc);
692 if (real_user == NULL) {
693 debug_print(ctx, 1, "Could not find user identity for "
694 "dmacc user '%s'", user);
699 cert = db_get_val(ctx, user, realm, "cert", dmacc);
700 if (cert && cert[0] == '\0')
703 cred = build_credential_cert(ctx, real_user ? real_user : user,
706 cred = build_credential(ctx, real_user ? real_user : user,
707 realm, new_pw, sizeof(new_pw));
711 debug_print(ctx, 1, "Could not build credential");
715 status = "Remediation complete, request sppUpdateResponse";
716 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
718 if (spp_node == NULL) {
719 debug_print(ctx, 1, "Could not build sppPostDevDataResponse");
723 snprintf(buf, sizeof(buf),
724 "./Wi-Fi/%s/PerProviderSubscription/Credential1/Credential",
727 if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
728 debug_print(ctx, 1, "Could not add update node");
729 xml_node_free(ctx->xml, spp_node);
733 hs20_eventlog_node(ctx, user, realm, session_id,
734 machine_rem ? "machine remediation" :
735 "user remediation", cred);
736 xml_node_free(ctx->xml, cred);
739 debug_print(ctx, 1, "Certificate credential - no need for DB "
740 "password update on success notification");
742 debug_print(ctx, 1, "Request DB password update on success "
744 db_add_session(ctx, user, realm, session_id, new_pw, NULL,
752 static xml_node_t * machine_remediation(struct hs20_svc *ctx,
755 const char *session_id, int dmacc)
757 return build_sub_rem_resp(ctx, user, realm, session_id, 1, dmacc);
761 static xml_node_t * policy_remediation(struct hs20_svc *ctx,
762 const char *user, const char *realm,
763 const char *session_id, int dmacc)
766 xml_node_t *spp_node, *policy;
770 hs20_eventlog(ctx, user, realm, session_id,
771 "requires policy remediation", NULL);
773 db_add_session(ctx, user, realm, session_id, NULL, NULL,
776 policy = build_policy(ctx, user, realm, dmacc);
778 return build_post_dev_data_response(
779 ctx, NULL, session_id,
780 "No update available at this time", NULL);
783 status = "Remediation complete, request sppUpdateResponse";
784 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
786 if (spp_node == NULL)
789 snprintf(buf, sizeof(buf),
790 "./Wi-Fi/%s/PerProviderSubscription/Credential1/Policy",
793 if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
794 xml_node_free(ctx->xml, spp_node);
795 xml_node_free(ctx->xml, policy);
799 hs20_eventlog_node(ctx, user, realm, session_id,
800 "policy update (sub rem)", policy);
801 xml_node_free(ctx->xml, policy);
807 static xml_node_t * browser_remediation(struct hs20_svc *ctx,
808 const char *session_id,
809 const char *redirect_uri,
813 xml_node_t *spp_node, *exec_node;
815 if (redirect_uri == NULL) {
816 debug_print(ctx, 1, "Missing redirectURI attribute for user "
820 debug_print(ctx, 1, "redirectURI %s", redirect_uri);
822 spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
824 if (spp_node == NULL)
827 exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
828 xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI",
834 static xml_node_t * user_remediation(struct hs20_svc *ctx, const char *user,
835 const char *realm, const char *session_id,
836 const char *redirect_uri)
840 hs20_eventlog(ctx, user, realm, session_id,
841 "requires user remediation", NULL);
842 val = db_get_osu_config_val(ctx, realm, "remediation_url");
846 db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
849 snprintf(uri, sizeof(uri), "%s%s", val, session_id);
851 return browser_remediation(ctx, session_id, redirect_uri, uri);
855 static xml_node_t * free_remediation(struct hs20_svc *ctx,
856 const char *user, const char *realm,
857 const char *session_id,
858 const char *redirect_uri)
862 hs20_eventlog(ctx, user, realm, session_id,
863 "requires free/public account remediation", NULL);
864 val = db_get_osu_config_val(ctx, realm, "free_remediation_url");
868 db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
871 snprintf(uri, sizeof(uri), "%s%s", val, session_id);
873 return browser_remediation(ctx, session_id, redirect_uri, uri);
877 static xml_node_t * no_sub_rem(struct hs20_svc *ctx,
878 const char *user, const char *realm,
879 const char *session_id)
883 hs20_eventlog(ctx, user, realm, session_id,
884 "no subscription mediation available", NULL);
886 status = "No update available at this time";
887 return build_post_dev_data_response(ctx, NULL, session_id, status,
892 static xml_node_t * hs20_subscription_remediation(struct hs20_svc *ctx,
895 const char *session_id,
897 const char *redirect_uri)
899 char *type, *identity;
903 identity = db_get_val(ctx, user, realm, "identity", dmacc);
904 if (identity == NULL || strlen(identity) == 0) {
905 hs20_eventlog(ctx, user, realm, session_id,
906 "user not found in database for remediation",
909 return build_post_dev_data_response(ctx, NULL, session_id,
915 free_account = db_get_osu_config_val(ctx, realm, "free_account");
916 if (free_account && strcmp(free_account, user) == 0) {
918 return no_sub_rem(ctx, user, realm, session_id);
922 type = db_get_val(ctx, user, realm, "remediation", dmacc);
923 if (type && strcmp(type, "free") != 0) {
926 val = db_get_val(ctx, user, realm, "shared", dmacc);
932 return no_sub_rem(ctx, user, realm, session_id);
935 if (type && strcmp(type, "user") == 0)
936 ret = user_remediation(ctx, user, realm, session_id,
938 else if (type && strcmp(type, "free") == 0)
939 ret = free_remediation(ctx, user, realm, session_id,
941 else if (type && strcmp(type, "policy") == 0)
942 ret = policy_remediation(ctx, user, realm, session_id, dmacc);
944 ret = machine_remediation(ctx, user, realm, session_id, dmacc);
951 static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
952 const char *realm, int use_dmacc)
956 xml_node_t *policy, *node;
958 policy_id = db_get_val(ctx, user, realm, "policy", use_dmacc);
959 if (policy_id == NULL || strlen(policy_id) == 0) {
961 policy_id = strdup("default");
962 if (policy_id == NULL)
966 snprintf(fname, sizeof(fname), "%s/spp/policy/%s.xml",
967 ctx->root_dir, policy_id);
969 debug_print(ctx, 1, "Use policy file %s", fname);
971 policy = node_from_file(ctx->xml, fname);
975 node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate/URI");
978 url = db_get_osu_config_val(ctx, realm, "policy_url");
980 xml_node_free(ctx->xml, policy);
983 xml_node_set_text(ctx->xml, node, url);
987 node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate");
988 if (node && use_dmacc) {
990 pw = db_get_val(ctx, user, realm, "osu_password", use_dmacc);
992 build_username_password(ctx, node, user, pw) == NULL) {
993 debug_print(ctx, 1, "Failed to add Policy/PolicyUpdate/"
996 xml_node_free(ctx->xml, policy);
1006 static xml_node_t * hs20_policy_update(struct hs20_svc *ctx,
1007 const char *user, const char *realm,
1008 const char *session_id, int dmacc)
1010 xml_namespace_t *ns;
1011 xml_node_t *spp_node;
1017 identity = db_get_val(ctx, user, realm, "identity", dmacc);
1018 if (identity == NULL || strlen(identity) == 0) {
1019 hs20_eventlog(ctx, user, realm, session_id,
1020 "user not found in database for policy update",
1023 return build_post_dev_data_response(ctx, NULL, session_id,
1029 policy = build_policy(ctx, user, realm, dmacc);
1031 return build_post_dev_data_response(
1032 ctx, NULL, session_id,
1033 "No update available at this time", NULL);
1036 db_add_session(ctx, user, realm, session_id, NULL, NULL, POLICY_UPDATE);
1038 status = "Update complete, request sppUpdateResponse";
1039 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1041 if (spp_node == NULL)
1044 snprintf(buf, sizeof(buf),
1045 "./Wi-Fi/%s/PerProviderSubscription/Credential1/Policy",
1048 if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
1049 xml_node_free(ctx->xml, spp_node);
1050 xml_node_free(ctx->xml, policy);
1054 hs20_eventlog_node(ctx, user, realm, session_id, "policy update",
1056 xml_node_free(ctx->xml, policy);
1062 static xml_node_t * spp_get_mo(struct hs20_svc *ctx, xml_node_t *node,
1063 const char *urn, int *valid, char **ret_err)
1065 xml_node_t *child, *tnds, *mo;
1075 xml_node_for_each_child(ctx->xml, child, node) {
1076 xml_node_for_each_check(ctx->xml, child);
1077 name = xml_node_get_localname(ctx->xml, child);
1078 if (strcmp(name, "moContainer") != 0)
1080 mo_urn = xml_node_get_attr_value_ns(ctx->xml, child, SPP_NS_URI,
1082 if (strcasecmp(urn, mo_urn) == 0) {
1083 xml_node_get_attr_value_free(ctx->xml, mo_urn);
1086 xml_node_get_attr_value_free(ctx->xml, mo_urn);
1092 debug_print(ctx, 1, "moContainer text for %s", urn);
1093 debug_dump_node(ctx, "moContainer", child);
1095 str = xml_node_get_text(ctx->xml, child);
1096 debug_print(ctx, 1, "moContainer payload: '%s'", str);
1097 tnds = xml_node_from_buf(ctx->xml, str);
1098 xml_node_get_text_free(ctx->xml, str);
1100 debug_print(ctx, 1, "could not parse moContainer text");
1104 snprintf(fname, sizeof(fname), "%s/spp/dm_ddf-v1_2.dtd", ctx->root_dir);
1105 if (xml_validate_dtd(ctx->xml, tnds, fname, ret_err) == 0)
1107 else if (ret_err && *ret_err &&
1108 os_strcmp(*ret_err, "No declaration for attribute xmlns of element MgmtTree\n") == 0) {
1110 debug_print(ctx, 1, "Ignore OMA-DM DDF DTD validation error for MgmtTree namespace declaration with xmlns attribute");
1116 mo = tnds_to_mo(ctx->xml, tnds);
1117 xml_node_free(ctx->xml, tnds);
1119 debug_print(ctx, 1, "invalid moContainer for %s", urn);
1126 static xml_node_t * spp_exec_upload_mo(struct hs20_svc *ctx,
1127 const char *session_id, const char *urn)
1129 xml_namespace_t *ns;
1130 xml_node_t *spp_node, *node, *exec_node;
1132 spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
1134 if (spp_node == NULL)
1137 exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
1139 node = xml_node_create(ctx->xml, exec_node, ns, "uploadMO");
1140 xml_node_add_attr(ctx->xml, node, ns, "moURN", urn);
1146 static xml_node_t * hs20_subscription_registration(struct hs20_svc *ctx,
1148 const char *session_id,
1149 const char *redirect_uri)
1151 xml_namespace_t *ns;
1152 xml_node_t *spp_node, *exec_node;
1153 char uri[300], *val;
1155 if (db_add_session(ctx, NULL, realm, session_id, NULL, redirect_uri,
1156 SUBSCRIPTION_REGISTRATION) < 0)
1158 val = db_get_osu_config_val(ctx, realm, "signup_url");
1162 spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
1164 if (spp_node == NULL)
1167 exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
1169 snprintf(uri, sizeof(uri), "%s%s", val, session_id);
1171 xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI",
1177 static xml_node_t * hs20_user_input_remediation(struct hs20_svc *ctx,
1179 const char *realm, int dmacc,
1180 const char *session_id)
1182 return build_sub_rem_resp(ctx, user, realm, session_id, 0, dmacc);
1186 static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm,
1190 struct get_db_field_data data;
1192 cmd = sqlite3_mprintf("SELECT value FROM osu_config WHERE realm=%Q AND "
1193 "field=%Q", realm, field);
1196 debug_print(ctx, 1, "DB: %s", cmd);
1197 memset(&data, 0, sizeof(data));
1198 data.field = "value";
1199 if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
1201 debug_print(ctx, 1, "DB: Could not find osu_config %s: %s",
1202 realm, sqlite3_errmsg(ctx->db));
1208 debug_print(ctx, 1, "DB: return '%s'", data.value);
1213 static xml_node_t * build_pps(struct hs20_svc *ctx,
1214 const char *user, const char *realm,
1215 const char *pw, const char *cert,
1216 int machine_managed)
1218 xml_node_t *pps, *c, *trust, *aaa, *aaa1, *upd, *homesp;
1219 xml_node_t *cred, *eap, *userpw;
1221 pps = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
1222 "PerProviderSubscription");
1226 add_text_node(ctx, pps, "UpdateIdentifier", "1");
1228 c = xml_node_create(ctx->xml, pps, NULL, "Credential1");
1230 add_text_node(ctx, c, "CredentialPriority", "1");
1232 aaa = xml_node_create(ctx->xml, c, NULL, "AAAServerTrustRoot");
1233 aaa1 = xml_node_create(ctx->xml, aaa, NULL, "AAA1");
1234 add_text_node_conf(ctx, realm, aaa1, "CertURL",
1235 "aaa_trust_root_cert_url");
1236 add_text_node_conf(ctx, realm, aaa1, "CertSHA256Fingerprint",
1237 "aaa_trust_root_cert_fingerprint");
1239 upd = xml_node_create(ctx->xml, c, NULL, "SubscriptionUpdate");
1240 add_text_node(ctx, upd, "UpdateInterval", "4294967295");
1241 add_text_node(ctx, upd, "UpdateMethod", "ClientInitiated");
1242 add_text_node(ctx, upd, "Restriction", "HomeSP");
1243 add_text_node_conf(ctx, realm, upd, "URI", "spp_http_auth_url");
1244 trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
1245 add_text_node_conf(ctx, realm, trust, "CertURL", "trust_root_cert_url");
1246 add_text_node_conf(ctx, realm, trust, "CertSHA256Fingerprint",
1247 "trust_root_cert_fingerprint");
1249 homesp = xml_node_create(ctx->xml, c, NULL, "HomeSP");
1250 add_text_node_conf(ctx, realm, homesp, "FriendlyName", "friendly_name");
1251 add_text_node_conf(ctx, realm, homesp, "FQDN", "fqdn");
1253 xml_node_create(ctx->xml, c, NULL, "SubscriptionParameters");
1255 cred = xml_node_create(ctx->xml, c, NULL, "Credential");
1256 add_creation_date(ctx, cred);
1259 dc = xml_node_create(ctx->xml, cred, NULL,
1260 "DigitalCertificate");
1261 add_text_node(ctx, dc, "CertificateType", "x509v3");
1262 add_text_node(ctx, dc, "CertSHA256Fingerprint", cert);
1264 userpw = build_username_password(ctx, cred, user, pw);
1265 add_text_node(ctx, userpw, "MachineManaged",
1266 machine_managed ? "TRUE" : "FALSE");
1267 eap = xml_node_create(ctx->xml, userpw, NULL, "EAPMethod");
1268 add_text_node(ctx, eap, "EAPType", "21");
1269 add_text_node(ctx, eap, "InnerMethod", "MS-CHAP-V2");
1271 add_text_node(ctx, cred, "Realm", realm);
1277 static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx,
1278 const char *session_id,
1282 xml_namespace_t *ns;
1283 xml_node_t *spp_node, *enroll, *exec_node;
1288 if (new_password(password, sizeof(password)) < 0)
1291 spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
1293 if (spp_node == NULL)
1296 exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
1298 enroll = xml_node_create(ctx->xml, exec_node, ns, "getCertificate");
1299 xml_node_add_attr(ctx->xml, enroll, NULL, "enrollmentProtocol", "EST");
1301 val = db_get_osu_config_val(ctx, realm, "est_url");
1302 xml_node_create_text(ctx->xml, enroll, ns, "enrollmentServerURI",
1305 xml_node_create_text(ctx->xml, enroll, ns, "estUserID", user);
1307 b64 = (char *) base64_encode((unsigned char *) password,
1308 strlen(password), NULL);
1310 xml_node_free(ctx->xml, spp_node);
1313 xml_node_create_text(ctx->xml, enroll, ns, "estPassword", b64);
1316 db_update_session_password(ctx, user, realm, session_id, password);
1322 static xml_node_t * hs20_user_input_registration(struct hs20_svc *ctx,
1323 const char *session_id,
1324 int enrollment_done)
1326 xml_namespace_t *ns;
1327 xml_node_t *spp_node, *node = NULL;
1328 xml_node_t *pps, *tnds;
1331 char *user, *realm, *pw, *type, *mm;
1334 int machine_managed = 0;
1337 user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
1338 realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
1339 pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
1341 if (!user || !realm || !pw) {
1342 debug_print(ctx, 1, "Could not find session info from DB for "
1343 "the new subscription");
1350 mm = db_get_session_val(ctx, NULL, NULL, session_id, "machine_managed");
1352 machine_managed = 1;
1355 type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
1356 if (type && strcmp(type, "cert") == 0)
1360 if (cert && !enrollment_done) {
1362 hs20_eventlog(ctx, user, realm, session_id,
1363 "request client certificate enrollment", NULL);
1364 ret = spp_exec_get_certificate(ctx, session_id, user, realm);
1371 if (!cert && strlen(pw) == 0) {
1372 machine_managed = 1;
1375 if (pw == NULL || new_password(pw, 11) < 0) {
1383 status = "Provisioning complete, request sppUpdateResponse";
1384 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1386 if (spp_node == NULL)
1389 fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
1390 pps = build_pps(ctx, user, realm, pw,
1391 fingerprint ? fingerprint : NULL, machine_managed);
1394 xml_node_free(ctx->xml, spp_node);
1401 debug_print(ctx, 1, "Request DB subscription registration on success "
1403 if (machine_managed) {
1404 db_update_session_password(ctx, user, realm, session_id, pw);
1405 db_update_session_machine_managed(ctx, user, realm, session_id,
1408 db_add_session_pps(ctx, user, realm, session_id, pps);
1410 hs20_eventlog_node(ctx, user, realm, session_id,
1411 "new subscription", pps);
1415 tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL);
1416 xml_node_free(ctx->xml, pps);
1418 xml_node_free(ctx->xml, spp_node);
1423 str = xml_node_to_str(ctx->xml, tnds);
1424 xml_node_free(ctx->xml, tnds);
1426 xml_node_free(ctx->xml, spp_node);
1431 node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str);
1433 snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm);
1435 xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf);
1436 xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS);
1442 static xml_node_t * hs20_user_input_free_remediation(struct hs20_svc *ctx,
1445 const char *session_id)
1447 xml_namespace_t *ns;
1448 xml_node_t *spp_node;
1452 char *free_account, *pw;
1454 free_account = db_get_osu_config_val(ctx, realm, "free_account");
1455 if (free_account == NULL)
1457 pw = db_get_val(ctx, free_account, realm, "password", 0);
1463 cred = build_credential_pw(ctx, free_account, realm, pw);
1467 xml_node_free(ctx->xml, cred);
1471 status = "Remediation complete, request sppUpdateResponse";
1472 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1474 if (spp_node == NULL)
1477 snprintf(buf, sizeof(buf),
1478 "./Wi-Fi/%s/PerProviderSubscription/Credential1/Credential",
1481 if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
1482 xml_node_free(ctx->xml, spp_node);
1486 hs20_eventlog_node(ctx, user, realm, session_id,
1487 "free/public remediation", cred);
1488 xml_node_free(ctx->xml, cred);
1494 static xml_node_t * hs20_user_input_complete(struct hs20_svc *ctx,
1496 const char *realm, int dmacc,
1497 const char *session_id)
1500 enum hs20_session_operation oper;
1502 val = db_get_session_val(ctx, user, realm, session_id, "operation");
1504 debug_print(ctx, 1, "No session %s found to continue",
1511 if (oper == USER_REMEDIATION) {
1512 return hs20_user_input_remediation(ctx, user, realm, dmacc,
1516 if (oper == FREE_REMEDIATION) {
1517 return hs20_user_input_free_remediation(ctx, user, realm,
1521 if (oper == SUBSCRIPTION_REGISTRATION) {
1522 return hs20_user_input_registration(ctx, session_id, 0);
1525 debug_print(ctx, 1, "User session %s not in state for user input "
1526 "completion", session_id);
1531 static xml_node_t * hs20_cert_enroll_completed(struct hs20_svc *ctx,
1533 const char *realm, int dmacc,
1534 const char *session_id)
1537 enum hs20_session_operation oper;
1539 val = db_get_session_val(ctx, user, realm, session_id, "operation");
1541 debug_print(ctx, 1, "No session %s found to continue",
1548 if (oper == SUBSCRIPTION_REGISTRATION)
1549 return hs20_user_input_registration(ctx, session_id, 1);
1551 debug_print(ctx, 1, "User session %s not in state for certificate "
1552 "enrollment completion", session_id);
1557 static xml_node_t * hs20_cert_enroll_failed(struct hs20_svc *ctx,
1559 const char *realm, int dmacc,
1560 const char *session_id)
1563 enum hs20_session_operation oper;
1564 xml_node_t *spp_node, *node;
1566 xml_namespace_t *ns;
1568 val = db_get_session_val(ctx, user, realm, session_id, "operation");
1570 debug_print(ctx, 1, "No session %s found to continue",
1577 if (oper != SUBSCRIPTION_REGISTRATION) {
1578 debug_print(ctx, 1, "User session %s not in state for "
1579 "enrollment failure", session_id);
1583 status = "Error occurred";
1584 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1586 if (spp_node == NULL)
1588 node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
1589 xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
1590 "Credentials cannot be provisioned at this time");
1591 db_remove_session(ctx, user, realm, session_id);
1597 static xml_node_t * hs20_spp_post_dev_data(struct hs20_svc *ctx,
1601 const char *session_id,
1604 const char *req_reason;
1605 char *redirect_uri = NULL;
1606 char *req_reason_buf = NULL;
1608 xml_node_t *ret = NULL, *devinfo = NULL, *devdetail = NULL;
1615 version = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
1617 if (version == NULL || strstr(version, "1.0") == NULL) {
1618 ret = build_post_dev_data_response(
1619 ctx, NULL, session_id, "Error occurred",
1620 "SPP version not supported");
1621 hs20_eventlog_node(ctx, user, realm, session_id,
1622 "Unsupported sppVersion", ret);
1623 xml_node_get_attr_value_free(ctx->xml, version);
1626 xml_node_get_attr_value_free(ctx->xml, version);
1628 mo = get_node(ctx->xml, node, "supportedMOList");
1630 ret = build_post_dev_data_response(
1631 ctx, NULL, session_id, "Error occurred",
1633 hs20_eventlog_node(ctx, user, realm, session_id,
1634 "No supportedMOList element", ret);
1637 supp = xml_node_get_text(ctx->xml, mo);
1638 for (pos = supp; pos && *pos; pos++)
1639 *pos = tolower(*pos);
1641 strstr(supp, URN_OMA_DM_DEVINFO) == NULL ||
1642 strstr(supp, URN_OMA_DM_DEVDETAIL) == NULL ||
1643 strstr(supp, URN_HS20_PPS) == NULL) {
1644 xml_node_get_text_free(ctx->xml, supp);
1645 ret = build_post_dev_data_response(
1646 ctx, NULL, session_id, "Error occurred",
1647 "One or more mandatory MOs not supported");
1648 hs20_eventlog_node(ctx, user, realm, session_id,
1649 "Unsupported MOs", ret);
1652 xml_node_get_text_free(ctx->xml, supp);
1654 req_reason_buf = xml_node_get_attr_value(ctx->xml, node,
1656 if (req_reason_buf == NULL) {
1657 debug_print(ctx, 1, "No requestReason attribute");
1660 req_reason = req_reason_buf;
1662 redirect_uri = xml_node_get_attr_value(ctx->xml, node, "redirectURI");
1664 debug_print(ctx, 1, "requestReason: %s sessionID: %s redirectURI: %s",
1665 req_reason, session_id, redirect_uri);
1666 snprintf(str, sizeof(str), "sppPostDevData: requestReason=%s",
1668 hs20_eventlog(ctx, user, realm, session_id, str, NULL);
1670 devinfo = spp_get_mo(ctx, node, URN_OMA_DM_DEVINFO, &valid, &err);
1671 if (devinfo == NULL) {
1672 ret = build_post_dev_data_response(ctx, NULL, session_id,
1673 "Error occurred", "Other");
1674 hs20_eventlog_node(ctx, user, realm, session_id,
1675 "No DevInfo moContainer in sppPostDevData",
1681 hs20_eventlog_node(ctx, user, realm, session_id,
1682 "Received DevInfo MO", devinfo);
1684 hs20_eventlog(ctx, user, realm, session_id,
1685 "OMA-DM DDF DTD validation errors in DevInfo MO",
1687 ret = build_post_dev_data_response(ctx, NULL, session_id,
1688 "Error occurred", "Other");
1694 db_update_mo(ctx, user, realm, "devinfo", devinfo);
1696 devdetail = spp_get_mo(ctx, node, URN_OMA_DM_DEVDETAIL, &valid, &err);
1697 if (devdetail == NULL) {
1698 ret = build_post_dev_data_response(ctx, NULL, session_id,
1699 "Error occurred", "Other");
1700 hs20_eventlog_node(ctx, user, realm, session_id,
1701 "No DevDetail moContainer in sppPostDevData",
1707 hs20_eventlog_node(ctx, user, realm, session_id,
1708 "Received DevDetail MO", devdetail);
1710 hs20_eventlog(ctx, user, realm, session_id,
1711 "OMA-DM DDF DTD validation errors "
1712 "in DevDetail MO", err);
1713 ret = build_post_dev_data_response(ctx, NULL, session_id,
1714 "Error occurred", "Other");
1720 db_update_mo(ctx, user, realm, "devdetail", devdetail);
1723 mo = spp_get_mo(ctx, node, URN_HS20_PPS, &valid, &err);
1729 hs20_eventlog_node(ctx, user, realm, session_id,
1730 "Received PPS MO", mo);
1732 hs20_eventlog(ctx, user, realm, session_id,
1733 "OMA-DM DDF DTD validation errors "
1735 xml_node_get_attr_value_free(ctx->xml, redirect_uri);
1737 return build_post_dev_data_response(
1738 ctx, NULL, session_id,
1739 "Error occurred", "Other");
1741 db_update_mo(ctx, user, realm, "pps", mo);
1742 db_update_val(ctx, user, realm, "fetch_pps", "0", dmacc);
1743 xml_node_free(ctx->xml, mo);
1751 fetch = db_get_val(ctx, user, realm, "fetch_pps", dmacc);
1752 fetch_pps = fetch ? atoi(fetch) : 0;
1756 enum hs20_session_operation oper;
1757 if (strcasecmp(req_reason, "Subscription remediation")
1759 oper = CONTINUE_SUBSCRIPTION_REMEDIATION;
1760 else if (strcasecmp(req_reason, "Policy update") == 0)
1761 oper = CONTINUE_POLICY_UPDATE;
1763 oper = NO_OPERATION;
1764 if (db_add_session(ctx, user, realm, session_id, NULL,
1768 ret = spp_exec_upload_mo(ctx, session_id,
1770 hs20_eventlog_node(ctx, user, realm, session_id,
1771 "request PPS MO upload",
1777 if (user && strcasecmp(req_reason, "MO upload") == 0) {
1778 char *val = db_get_session_val(ctx, user, realm, session_id,
1780 enum hs20_session_operation oper;
1782 debug_print(ctx, 1, "No session %s found to continue",
1788 if (oper == CONTINUE_SUBSCRIPTION_REMEDIATION)
1789 req_reason = "Subscription remediation";
1790 else if (oper == CONTINUE_POLICY_UPDATE)
1791 req_reason = "Policy update";
1794 "No pending operation in session %s",
1800 if (strcasecmp(req_reason, "Subscription registration") == 0) {
1801 ret = hs20_subscription_registration(ctx, realm, session_id,
1803 hs20_eventlog_node(ctx, user, realm, session_id,
1804 "subscription registration response",
1808 if (user && strcasecmp(req_reason, "Subscription remediation") == 0) {
1809 ret = hs20_subscription_remediation(ctx, user, realm,
1812 hs20_eventlog_node(ctx, user, realm, session_id,
1813 "subscription remediation response",
1817 if (user && strcasecmp(req_reason, "Policy update") == 0) {
1818 ret = hs20_policy_update(ctx, user, realm, session_id, dmacc);
1819 hs20_eventlog_node(ctx, user, realm, session_id,
1820 "policy update response",
1825 if (strcasecmp(req_reason, "User input completed") == 0) {
1827 db_add_session_devinfo(ctx, session_id, devinfo);
1829 db_add_session_devdetail(ctx, session_id, devdetail);
1830 ret = hs20_user_input_complete(ctx, user, realm, dmacc,
1832 hs20_eventlog_node(ctx, user, realm, session_id,
1833 "user input completed response", ret);
1837 if (strcasecmp(req_reason, "Certificate enrollment completed") == 0) {
1838 ret = hs20_cert_enroll_completed(ctx, user, realm, dmacc,
1840 hs20_eventlog_node(ctx, user, realm, session_id,
1841 "certificate enrollment response", ret);
1845 if (strcasecmp(req_reason, "Certificate enrollment failed") == 0) {
1846 ret = hs20_cert_enroll_failed(ctx, user, realm, dmacc,
1848 hs20_eventlog_node(ctx, user, realm, session_id,
1849 "certificate enrollment failed response",
1854 debug_print(ctx, 1, "Unsupported requestReason '%s' user '%s'",
1857 xml_node_get_attr_value_free(ctx->xml, req_reason_buf);
1858 xml_node_get_attr_value_free(ctx->xml, redirect_uri);
1860 xml_node_free(ctx->xml, devinfo);
1862 xml_node_free(ctx->xml, devdetail);
1867 static xml_node_t * build_spp_exchange_complete(struct hs20_svc *ctx,
1868 const char *session_id,
1870 const char *error_code)
1872 xml_namespace_t *ns;
1873 xml_node_t *spp_node, *node;
1875 spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
1876 "sppExchangeComplete");
1879 xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
1880 xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
1881 xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
1884 node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
1885 xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
1893 static int add_subscription(struct hs20_svc *ctx, const char *session_id)
1895 char *user, *realm, *pw, *pw_mm, *pps, *str;
1902 char *cert_pem, *fingerprint;
1904 user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
1905 realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
1906 pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
1907 pw_mm = db_get_session_val(ctx, NULL, NULL, session_id,
1909 pps = db_get_session_val(ctx, NULL, NULL, session_id, "pps");
1910 cert_pem = db_get_session_val(ctx, NULL, NULL, session_id, "cert_pem");
1911 fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
1912 type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
1913 if (type && strcmp(type, "cert") == 0)
1917 if (!user || !realm || !pw) {
1918 debug_print(ctx, 1, "Could not find session info from DB for "
1919 "the new subscription");
1923 free_account = db_get_osu_config_val(ctx, realm, "free_account");
1924 free_acc = free_account && strcmp(free_account, user) == 0;
1928 "New subscription: user='%s' realm='%s' free_acc=%d",
1929 user, realm, free_acc);
1930 debug_print(ctx, 1, "New subscription: pps='%s'", pps);
1932 sql = sqlite3_mprintf("UPDATE eventlog SET user=%Q, realm=%Q WHERE "
1933 "sessionid=%Q AND (user='' OR user IS NULL)",
1934 user, realm, session_id);
1936 debug_print(ctx, 1, "DB: %s", sql);
1937 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
1938 debug_print(ctx, 1, "Failed to update eventlog in "
1939 "sqlite database: %s",
1940 sqlite3_errmsg(ctx->db));
1946 hs20_eventlog(ctx, user, realm, session_id,
1947 "completed shared free account registration",
1953 sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,"
1954 "methods,cert,cert_pem,machine_managed) VALUES "
1955 "(%Q,%Q,1,%Q,%Q,%Q,%d)",
1956 user, realm, cert ? "TLS" : "TTLS-MSCHAPV2",
1957 fingerprint ? fingerprint : "",
1958 cert_pem ? cert_pem : "",
1959 pw_mm && atoi(pw_mm) ? 1 : 0);
1962 debug_print(ctx, 1, "DB: %s", sql);
1963 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
1964 debug_print(ctx, 1, "Failed to add user in sqlite database: %s",
1965 sqlite3_errmsg(ctx->db));
1974 ret = update_password(ctx, user, realm, pw, 0);
1976 sql = sqlite3_mprintf("DELETE FROM users WHERE identity=%Q AND "
1977 "realm=%Q AND phase2=1",
1980 debug_print(ctx, 1, "DB: %s", sql);
1981 sqlite3_exec(ctx->db, sql, NULL, NULL, NULL);
1987 db_update_mo_str(ctx, user, realm, "pps", pps);
1989 str = db_get_session_val(ctx, NULL, NULL, session_id, "devinfo");
1991 db_update_mo_str(ctx, user, realm, "devinfo", str);
1995 str = db_get_session_val(ctx, NULL, NULL, session_id, "devdetail");
1997 db_update_mo_str(ctx, user, realm, "devdetail", str);
2002 hs20_eventlog(ctx, user, realm, session_id,
2003 "completed subscription registration", NULL);
2018 static xml_node_t * hs20_spp_update_response(struct hs20_svc *ctx,
2022 const char *session_id,
2028 enum hs20_session_operation oper;
2030 status = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
2032 if (status == NULL) {
2033 debug_print(ctx, 1, "No sppStatus attribute");
2037 debug_print(ctx, 1, "sppUpdateResponse: sppStatus: %s sessionID: %s",
2038 status, session_id);
2040 val = db_get_session_val(ctx, user, realm, session_id, "operation");
2043 "No session active for user: %s sessionID: %s",
2045 oper = NO_OPERATION;
2049 if (strcasecmp(status, "OK") == 0) {
2050 char *new_pw = NULL;
2052 xml_node_get_attr_value_free(ctx->xml, status);
2054 if (oper == USER_REMEDIATION) {
2055 new_pw = db_get_session_val(ctx, user, realm,
2056 session_id, "password");
2057 if (new_pw == NULL || strlen(new_pw) == 0) {
2059 ret = build_spp_exchange_complete(
2060 ctx, session_id, "Error occurred",
2062 hs20_eventlog_node(ctx, user, realm,
2063 session_id, "No password "
2064 "had been assigned for "
2066 db_remove_session(ctx, user, realm, session_id);
2069 oper = UPDATE_PASSWORD;
2071 if (oper == UPDATE_PASSWORD) {
2073 new_pw = db_get_session_val(ctx, user, realm,
2077 db_remove_session(ctx, user, realm,
2082 debug_print(ctx, 1, "Update user '%s' password in DB",
2084 if (update_password(ctx, user, realm, new_pw, dmacc) <
2086 debug_print(ctx, 1, "Failed to update user "
2087 "'%s' password in DB", user);
2088 ret = build_spp_exchange_complete(
2089 ctx, session_id, "Error occurred",
2091 hs20_eventlog_node(ctx, user, realm,
2092 session_id, "Failed to "
2093 "update database", ret);
2094 db_remove_session(ctx, user, realm, session_id);
2097 hs20_eventlog(ctx, user, realm,
2098 session_id, "Updated user password "
2099 "in database", NULL);
2101 if (oper == SUBSCRIPTION_REGISTRATION) {
2102 if (add_subscription(ctx, session_id) < 0) {
2103 debug_print(ctx, 1, "Failed to add "
2104 "subscription into DB");
2105 ret = build_spp_exchange_complete(
2106 ctx, session_id, "Error occurred",
2108 hs20_eventlog_node(ctx, user, realm,
2109 session_id, "Failed to "
2110 "update database", ret);
2111 db_remove_session(ctx, user, realm, session_id);
2115 if (oper == POLICY_REMEDIATION || oper == POLICY_UPDATE) {
2117 val = db_get_val(ctx, user, realm, "remediation",
2119 if (val && strcmp(val, "policy") == 0)
2120 db_update_val(ctx, user, realm, "remediation",
2124 ret = build_spp_exchange_complete(
2126 "Exchange complete, release TLS connection", NULL);
2127 hs20_eventlog_node(ctx, user, realm, session_id,
2128 "Exchange completed", ret);
2129 db_remove_session(ctx, user, realm, session_id);
2133 ret = build_spp_exchange_complete(ctx, session_id, "Error occurred",
2135 hs20_eventlog_node(ctx, user, realm, session_id, "Error occurred", ret);
2136 db_remove_session(ctx, user, realm, session_id);
2137 xml_node_get_attr_value_free(ctx->xml, status);
2142 #define SPP_SESSION_ID_LEN 16
2144 static char * gen_spp_session_id(void)
2150 session = os_malloc(SPP_SESSION_ID_LEN * 2 + 1);
2151 if (session == NULL)
2154 f = fopen("/dev/urandom", "r");
2159 for (i = 0; i < SPP_SESSION_ID_LEN; i++)
2160 os_snprintf(session + i * 2, 3, "%02x", fgetc(f));
2166 xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node,
2167 const char *auth_user,
2168 const char *auth_realm, int dmacc)
2170 xml_node_t *ret = NULL;
2172 const char *op_name;
2176 debug_dump_node(ctx, "received request", node);
2178 if (!dmacc && auth_user && auth_realm) {
2180 real = db_get_val(ctx, auth_user, auth_realm, "identity", 0);
2182 real = db_get_val(ctx, auth_user, auth_realm,
2190 snprintf(fname, sizeof(fname), "%s/spp/spp.xsd", ctx->root_dir);
2191 if (xml_validate(ctx->xml, node, fname, &xml_err) < 0) {
2193 * We may not be able to extract the sessionID from invalid
2194 * input, but well, we can try.
2196 session_id = xml_node_get_attr_value_ns(ctx->xml, node,
2200 "SPP message failed validation, xsd file: %s xml-error: %s",
2202 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2203 "SPP message failed validation", node);
2204 hs20_eventlog(ctx, auth_user, auth_realm, session_id,
2205 "Validation errors", xml_err);
2207 xml_node_get_attr_value_free(ctx->xml, session_id);
2208 /* TODO: what to return here? */
2209 ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2210 "SppValidationError");
2214 session_id = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
2218 debug_print(ctx, 1, "Received sessionID %s", session_id);
2219 tmp = os_strdup(session_id);
2220 xml_node_get_attr_value_free(ctx->xml, session_id);
2225 session_id = gen_spp_session_id();
2226 if (session_id == NULL) {
2227 debug_print(ctx, 1, "Failed to generate sessionID");
2230 debug_print(ctx, 1, "Generated sessionID %s", session_id);
2233 op_name = xml_node_get_localname(ctx->xml, node);
2234 if (op_name == NULL) {
2235 debug_print(ctx, 1, "Could not get op_name");
2239 if (strcmp(op_name, "sppPostDevData") == 0) {
2240 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2241 "sppPostDevData received and validated",
2243 ret = hs20_spp_post_dev_data(ctx, node, auth_user, auth_realm,
2245 } else if (strcmp(op_name, "sppUpdateResponse") == 0) {
2246 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2247 "sppUpdateResponse received and validated",
2249 ret = hs20_spp_update_response(ctx, node, auth_user,
2250 auth_realm, session_id, dmacc);
2252 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2253 "Unsupported SPP message received and "
2255 debug_print(ctx, 1, "Unsupported operation '%s'", op_name);
2256 /* TODO: what to return here? */
2257 ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2258 "SppUnknownCommandError");
2260 os_free(session_id);
2263 /* TODO: what to return here? */
2264 ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2265 "SppInternalError");
2272 int hs20_spp_server_init(struct hs20_svc *ctx)
2276 snprintf(fname, sizeof(fname), "%s/AS/DB/eap_user.db", ctx->root_dir);
2277 if (sqlite3_open(fname, &ctx->db)) {
2278 printf("Failed to open sqlite database: %s\n",
2279 sqlite3_errmsg(ctx->db));
2280 sqlite3_close(ctx->db);
2288 void hs20_spp_server_deinit(struct hs20_svc *ctx)
2290 sqlite3_close(ctx->db);