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