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