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 	CLEAR_REMEDIATION,
     45 	CERT_REENROLL,
     46 };
     47 
     48 
     49 static char * db_get_session_val(struct hs20_svc *ctx, const char *user,
     50 				 const char *realm, const char *session_id,
     51 				 const char *field);
     52 static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm,
     53 				    const char *field);
     54 static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
     55 				 const char *realm, int use_dmacc);
     56 static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx,
     57 					     const char *session_id,
     58 					     const char *user,
     59 					     const char *realm,
     60 					     int add_est_user);
     61 
     62 
     63 static int db_add_session(struct hs20_svc *ctx,
     64 			  const char *user, const char *realm,
     65 			  const char *sessionid, const char *pw,
     66 			  const char *redirect_uri,
     67 			  enum hs20_session_operation operation,
     68 			  const u8 *mac_addr)
     69 {
     70 	char *sql;
     71 	int ret = 0;
     72 	char addr[20];
     73 
     74 	if (mac_addr)
     75 		snprintf(addr, sizeof(addr), MACSTR, MAC2STR(mac_addr));
     76 	else
     77 		addr[0] = '\0';
     78 	sql = sqlite3_mprintf("INSERT INTO sessions(timestamp,id,user,realm,"
     79 			      "operation,password,redirect_uri,mac_addr,test) "
     80 			      "VALUES "
     81 			      "(strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
     82 			      "%Q,%Q,%Q,%d,%Q,%Q,%Q,%Q)",
     83 			      sessionid, user ? user : "", realm ? realm : "",
     84 			      operation, pw ? pw : "",
     85 			      redirect_uri ? redirect_uri : "",
     86 			      addr, ctx->test);
     87 	if (sql == NULL)
     88 		return -1;
     89 	debug_print(ctx, 1, "DB: %s", sql);
     90 	if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
     91 		debug_print(ctx, 1, "Failed to add session entry into sqlite "
     92 			    "database: %s", sqlite3_errmsg(ctx->db));
     93 		ret = -1;
     94 	}
     95 	sqlite3_free(sql);
     96 	return ret;
     97 }
     98 
     99 
    100 static void db_update_session_password(struct hs20_svc *ctx, const char *user,
    101 				       const char *realm, const char *sessionid,
    102 				       const char *pw)
    103 {
    104 	char *sql;
    105 
    106 	sql = sqlite3_mprintf("UPDATE sessions SET password=%Q WHERE id=%Q AND "
    107 			      "user=%Q AND realm=%Q",
    108 			      pw, sessionid, user, realm);
    109 	if (sql == NULL)
    110 		return;
    111 	debug_print(ctx, 1, "DB: %s", sql);
    112 	if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
    113 		debug_print(ctx, 1, "Failed to update session password: %s",
    114 			    sqlite3_errmsg(ctx->db));
    115 	}
    116 	sqlite3_free(sql);
    117 }
    118 
    119 
    120 static void db_update_session_machine_managed(struct hs20_svc *ctx,
    121 					      const char *user,
    122 					      const char *realm,
    123 					      const char *sessionid,
    124 					      const int pw_mm)
    125 {
    126 	char *sql;
    127 
    128 	sql = sqlite3_mprintf("UPDATE sessions SET machine_managed=%Q WHERE id=%Q AND user=%Q AND realm=%Q",
    129 			      pw_mm ? "1" : "0", sessionid, user, realm);
    130 	if (sql == NULL)
    131 		return;
    132 	debug_print(ctx, 1, "DB: %s", sql);
    133 	if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
    134 		debug_print(ctx, 1,
    135 			    "Failed to update session machine_managed: %s",
    136 			    sqlite3_errmsg(ctx->db));
    137 	}
    138 	sqlite3_free(sql);
    139 }
    140 
    141 
    142 static void db_add_session_pps(struct hs20_svc *ctx, const char *user,
    143 			       const char *realm, const char *sessionid,
    144 			       xml_node_t *node)
    145 {
    146 	char *str;
    147 	char *sql;
    148 
    149 	str = xml_node_to_str(ctx->xml, node);
    150 	if (str == NULL)
    151 		return;
    152 	sql = sqlite3_mprintf("UPDATE sessions SET pps=%Q WHERE id=%Q AND "
    153 			      "user=%Q AND realm=%Q",
    154 			      str, sessionid, user, realm);
    155 	free(str);
    156 	if (sql == NULL)
    157 		return;
    158 	debug_print(ctx, 1, "DB: %s", sql);
    159 	if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
    160 		debug_print(ctx, 1, "Failed to add session pps: %s",
    161 			    sqlite3_errmsg(ctx->db));
    162 	}
    163 	sqlite3_free(sql);
    164 }
    165 
    166 
    167 static void db_add_session_devinfo(struct hs20_svc *ctx, const char *sessionid,
    168 				   xml_node_t *node)
    169 {
    170 	char *str;
    171 	char *sql;
    172 
    173 	str = xml_node_to_str(ctx->xml, node);
    174 	if (str == NULL)
    175 		return;
    176 	sql = sqlite3_mprintf("UPDATE sessions SET devinfo=%Q WHERE id=%Q",
    177 			      str, sessionid);
    178 	free(str);
    179 	if (sql == NULL)
    180 		return;
    181 	debug_print(ctx, 1, "DB: %s", sql);
    182 	if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
    183 		debug_print(ctx, 1, "Failed to add session devinfo: %s",
    184 			    sqlite3_errmsg(ctx->db));
    185 	}
    186 	sqlite3_free(sql);
    187 }
    188 
    189 
    190 static void db_add_session_devdetail(struct hs20_svc *ctx,
    191 				     const char *sessionid,
    192 				     xml_node_t *node)
    193 {
    194 	char *str;
    195 	char *sql;
    196 
    197 	str = xml_node_to_str(ctx->xml, node);
    198 	if (str == NULL)
    199 		return;
    200 	sql = sqlite3_mprintf("UPDATE sessions SET devdetail=%Q WHERE id=%Q",
    201 			      str, sessionid);
    202 	free(str);
    203 	if (sql == NULL)
    204 		return;
    205 	debug_print(ctx, 1, "DB: %s", sql);
    206 	if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
    207 		debug_print(ctx, 1, "Failed to add session devdetail: %s",
    208 			    sqlite3_errmsg(ctx->db));
    209 	}
    210 	sqlite3_free(sql);
    211 }
    212 
    213 
    214 static void db_add_session_dmacc(struct hs20_svc *ctx, const char *sessionid,
    215 				 const char *username, const char *password)
    216 {
    217 	char *sql;
    218 
    219 	sql = sqlite3_mprintf("UPDATE sessions SET osu_user=%Q, osu_password=%Q WHERE id=%Q",
    220 			      username, password, sessionid);
    221 	if (!sql)
    222 		return;
    223 	debug_print(ctx, 1, "DB: %s", sql);
    224 	if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
    225 		debug_print(ctx, 1, "Failed to add session DMAcc: %s",
    226 			    sqlite3_errmsg(ctx->db));
    227 	}
    228 	sqlite3_free(sql);
    229 }
    230 
    231 
    232 static void db_add_session_eap_method(struct hs20_svc *ctx,
    233 				      const char *sessionid,
    234 				      const char *method)
    235 {
    236 	char *sql;
    237 
    238 	sql = sqlite3_mprintf("UPDATE sessions SET eap_method=%Q WHERE id=%Q",
    239 			      method, sessionid);
    240 	if (!sql)
    241 		return;
    242 	debug_print(ctx, 1, "DB: %s", sql);
    243 	if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
    244 		debug_print(ctx, 1, "Failed to add session EAP method: %s",
    245 			    sqlite3_errmsg(ctx->db));
    246 	}
    247 	sqlite3_free(sql);
    248 }
    249 
    250 
    251 static void db_add_session_id_hash(struct hs20_svc *ctx, const char *sessionid,
    252 				   const char *id_hash)
    253 {
    254 	char *sql;
    255 
    256 	sql = sqlite3_mprintf("UPDATE sessions SET mobile_identifier_hash=%Q WHERE id=%Q",
    257 			      id_hash, sessionid);
    258 	if (!sql)
    259 		return;
    260 	debug_print(ctx, 1, "DB: %s", sql);
    261 	if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
    262 		debug_print(ctx, 1, "Failed to add session ID hash: %s",
    263 			    sqlite3_errmsg(ctx->db));
    264 	}
    265 	sqlite3_free(sql);
    266 }
    267 
    268 
    269 static void db_remove_session(struct hs20_svc *ctx,
    270 			      const char *user, const char *realm,
    271 			      const char *sessionid)
    272 {
    273 	char *sql;
    274 
    275 	if (user == NULL || realm == NULL) {
    276 		sql = sqlite3_mprintf("DELETE FROM sessions WHERE "
    277 				      "id=%Q", sessionid);
    278 	} else {
    279 		sql = sqlite3_mprintf("DELETE FROM sessions WHERE "
    280 				      "user=%Q AND realm=%Q AND id=%Q",
    281 				      user, realm, sessionid);
    282 	}
    283 	if (sql == NULL)
    284 		return;
    285 	debug_print(ctx, 1, "DB: %s", sql);
    286 	if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
    287 		debug_print(ctx, 1, "Failed to delete session entry from "
    288 			    "sqlite database: %s", sqlite3_errmsg(ctx->db));
    289 	}
    290 	sqlite3_free(sql);
    291 }
    292 
    293 
    294 static void hs20_eventlog(struct hs20_svc *ctx,
    295 			  const char *user, const char *realm,
    296 			  const char *sessionid, const char *notes,
    297 			  const char *dump)
    298 {
    299 	char *sql;
    300 	char *user_buf = NULL, *realm_buf = NULL;
    301 
    302 	debug_print(ctx, 1, "eventlog: %s", notes);
    303 
    304 	if (user == NULL) {
    305 		user_buf = db_get_session_val(ctx, NULL, NULL, sessionid,
    306 					      "user");
    307 		user = user_buf;
    308 		realm_buf = db_get_session_val(ctx, NULL, NULL, sessionid,
    309 					       "realm");
    310 		realm = realm_buf;
    311 	}
    312 
    313 	sql = sqlite3_mprintf("INSERT INTO eventlog"
    314 			      "(user,realm,sessionid,timestamp,notes,dump,addr)"
    315 			      " VALUES (%Q,%Q,%Q,"
    316 			      "strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
    317 			      "%Q,%Q,%Q)",
    318 			      user, realm, sessionid, notes,
    319 			      dump ? dump : "", ctx->addr ? ctx->addr : "");
    320 	free(user_buf);
    321 	free(realm_buf);
    322 	if (sql == NULL)
    323 		return;
    324 	if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
    325 		debug_print(ctx, 1, "Failed to add eventlog entry into sqlite "
    326 			    "database: %s", sqlite3_errmsg(ctx->db));
    327 	}
    328 	sqlite3_free(sql);
    329 }
    330 
    331 
    332 static void hs20_eventlog_node(struct hs20_svc *ctx,
    333 			       const char *user, const char *realm,
    334 			       const char *sessionid, const char *notes,
    335 			       xml_node_t *node)
    336 {
    337 	char *str;
    338 
    339 	if (node)
    340 		str = xml_node_to_str(ctx->xml, node);
    341 	else
    342 		str = NULL;
    343 	hs20_eventlog(ctx, user, realm, sessionid, notes, str);
    344 	free(str);
    345 }
    346 
    347 
    348 static void db_update_mo_str(struct hs20_svc *ctx, const char *user,
    349 			     const char *realm, const char *name,
    350 			     const char *str)
    351 {
    352 	char *sql;
    353 	if (user == NULL || realm == NULL || name == NULL)
    354 		return;
    355 	sql = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE identity=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
    356 			      name, str, user, realm);
    357 	if (sql == NULL)
    358 		return;
    359 	debug_print(ctx, 1, "DB: %s", sql);
    360 	if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
    361 		debug_print(ctx, 1, "Failed to update user MO entry in sqlite "
    362 			    "database: %s", sqlite3_errmsg(ctx->db));
    363 	}
    364 	sqlite3_free(sql);
    365 }
    366 
    367 
    368 static void db_update_mo(struct hs20_svc *ctx, const char *user,
    369 			 const char *realm, const char *name, xml_node_t *mo)
    370 {
    371 	char *str;
    372 
    373 	str = xml_node_to_str(ctx->xml, mo);
    374 	if (str == NULL)
    375 		return;
    376 
    377 	db_update_mo_str(ctx, user, realm, name, str);
    378 	free(str);
    379 }
    380 
    381 
    382 static void add_text_node(struct hs20_svc *ctx, xml_node_t *parent,
    383 			  const char *name, const char *value)
    384 {
    385 	xml_node_create_text(ctx->xml, parent, NULL, name, value ? value : "");
    386 }
    387 
    388 
    389 static void add_text_node_conf(struct hs20_svc *ctx, const char *realm,
    390 			       xml_node_t *parent, const char *name,
    391 			       const char *field)
    392 {
    393 	char *val;
    394 	val = db_get_osu_config_val(ctx, realm, field);
    395 	xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : "");
    396 	os_free(val);
    397 }
    398 
    399 
    400 static void add_text_node_conf_corrupt(struct hs20_svc *ctx, const char *realm,
    401 				       xml_node_t *parent, const char *name,
    402 				       const char *field)
    403 {
    404 	char *val;
    405 
    406 	val = db_get_osu_config_val(ctx, realm, field);
    407 	if (val) {
    408 		size_t len;
    409 
    410 		len = os_strlen(val);
    411 		if (len > 0) {
    412 			if (val[len - 1] == '0')
    413 				val[len - 1] = '1';
    414 			else
    415 				val[len - 1] = '0';
    416 		}
    417 	}
    418 	xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : "");
    419 	os_free(val);
    420 }
    421 
    422 
    423 static int new_password(char *buf, int buflen)
    424 {
    425 	int i;
    426 
    427 	if (buflen < 1)
    428 		return -1;
    429 	buf[buflen - 1] = '\0';
    430 	if (os_get_random((unsigned char *) buf, buflen - 1) < 0)
    431 		return -1;
    432 
    433 	for (i = 0; i < buflen - 1; i++) {
    434 		unsigned char val = buf[i];
    435 		val %= 2 * 26 + 10;
    436 		if (val < 26)
    437 			buf[i] = 'a' + val;
    438 		else if (val < 2 * 26)
    439 			buf[i] = 'A' + val - 26;
    440 		else
    441 			buf[i] = '0' + val - 2 * 26;
    442 	}
    443 
    444 	return 0;
    445 }
    446 
    447 
    448 struct get_db_field_data {
    449 	const char *field;
    450 	char *value;
    451 };
    452 
    453 
    454 static int get_db_field(void *ctx, int argc, char *argv[], char *col[])
    455 {
    456 	struct get_db_field_data *data = ctx;
    457 	int i;
    458 
    459 	for (i = 0; i < argc; i++) {
    460 		if (os_strcmp(col[i], data->field) == 0 && argv[i]) {
    461 			os_free(data->value);
    462 			data->value = os_strdup(argv[i]);
    463 			break;
    464 		}
    465 	}
    466 
    467 	return 0;
    468 }
    469 
    470 
    471 static char * db_get_val(struct hs20_svc *ctx, const char *user,
    472 			 const char *realm, const char *field, int dmacc)
    473 {
    474 	char *cmd;
    475 	struct get_db_field_data data;
    476 
    477 	cmd = sqlite3_mprintf("SELECT %s FROM users WHERE %s=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
    478 			      field, dmacc ? "osu_user" : "identity",
    479 			      user, realm);
    480 	if (cmd == NULL)
    481 		return NULL;
    482 	memset(&data, 0, sizeof(data));
    483 	data.field = field;
    484 	if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
    485 	{
    486 		debug_print(ctx, 1, "Could not find user '%s'", user);
    487 		sqlite3_free(cmd);
    488 		return NULL;
    489 	}
    490 	sqlite3_free(cmd);
    491 
    492 	debug_print(ctx, 1, "DB: user='%s' realm='%s' field='%s' dmacc=%d --> "
    493 		    "value='%s'", user, realm, field, dmacc, data.value);
    494 
    495 	return data.value;
    496 }
    497 
    498 
    499 static int db_update_val(struct hs20_svc *ctx, const char *user,
    500 			 const char *realm, const char *field,
    501 			 const char *val, int dmacc)
    502 {
    503 	char *cmd;
    504 	int ret;
    505 
    506 	cmd = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE %s=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
    507 			      field, val, dmacc ? "osu_user" : "identity", user,
    508 			      realm);
    509 	if (cmd == NULL)
    510 		return -1;
    511 	debug_print(ctx, 1, "DB: %s", cmd);
    512 	if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
    513 		debug_print(ctx, 1,
    514 			    "Failed to update user in sqlite database: %s",
    515 			    sqlite3_errmsg(ctx->db));
    516 		ret = -1;
    517 	} else {
    518 		debug_print(ctx, 1,
    519 			    "DB: user='%s' realm='%s' field='%s' set to '%s'",
    520 			    user, realm, field, val);
    521 		ret = 0;
    522 	}
    523 	sqlite3_free(cmd);
    524 
    525 	return ret;
    526 }
    527 
    528 
    529 static char * db_get_session_val(struct hs20_svc *ctx, const char *user,
    530 				 const char *realm, const char *session_id,
    531 				 const char *field)
    532 {
    533 	char *cmd;
    534 	struct get_db_field_data data;
    535 
    536 	if (user == NULL || realm == NULL) {
    537 		cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE "
    538 				      "id=%Q", field, session_id);
    539 	} else {
    540 		cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE "
    541 				      "user=%Q AND realm=%Q AND id=%Q",
    542 				      field, user, realm, session_id);
    543 	}
    544 	if (cmd == NULL)
    545 		return NULL;
    546 	debug_print(ctx, 1, "DB: %s", cmd);
    547 	memset(&data, 0, sizeof(data));
    548 	data.field = field;
    549 	if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
    550 	{
    551 		debug_print(ctx, 1, "DB: Could not find session %s: %s",
    552 			    session_id, sqlite3_errmsg(ctx->db));
    553 		sqlite3_free(cmd);
    554 		return NULL;
    555 	}
    556 	sqlite3_free(cmd);
    557 
    558 	debug_print(ctx, 1, "DB: return '%s'", data.value);
    559 	return data.value;
    560 }
    561 
    562 
    563 static int update_password(struct hs20_svc *ctx, const char *user,
    564 			   const char *realm, const char *pw, int dmacc)
    565 {
    566 	char *cmd;
    567 
    568 	cmd = sqlite3_mprintf("UPDATE users SET password=%Q, "
    569 			      "remediation='' "
    570 			      "WHERE %s=%Q AND phase2=1",
    571 			      pw, dmacc ? "osu_user" : "identity",
    572 			      user);
    573 	if (cmd == NULL)
    574 		return -1;
    575 	debug_print(ctx, 1, "DB: %s", cmd);
    576 	if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
    577 		debug_print(ctx, 1, "Failed to update database for user '%s'",
    578 			    user);
    579 	}
    580 	sqlite3_free(cmd);
    581 
    582 	return 0;
    583 }
    584 
    585 
    586 static int clear_remediation(struct hs20_svc *ctx, const char *user,
    587 			     const char *realm, int dmacc)
    588 {
    589 	char *cmd;
    590 
    591 	cmd = sqlite3_mprintf("UPDATE users SET remediation='' WHERE %s=%Q",
    592 			      dmacc ? "osu_user" : "identity",
    593 			      user);
    594 	if (cmd == NULL)
    595 		return -1;
    596 	debug_print(ctx, 1, "DB: %s", cmd);
    597 	if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
    598 		debug_print(ctx, 1, "Failed to update database for user '%s'",
    599 			    user);
    600 	}
    601 	sqlite3_free(cmd);
    602 
    603 	return 0;
    604 }
    605 
    606 
    607 static int add_eap_ttls(struct hs20_svc *ctx, xml_node_t *parent)
    608 {
    609 	xml_node_t *node;
    610 
    611 	node = xml_node_create(ctx->xml, parent, NULL, "EAPMethod");
    612 	if (node == NULL)
    613 		return -1;
    614 
    615 	add_text_node(ctx, node, "EAPType", "21");
    616 	add_text_node(ctx, node, "InnerMethod", "MS-CHAP-V2");
    617 
    618 	return 0;
    619 }
    620 
    621 
    622 static xml_node_t * build_username_password(struct hs20_svc *ctx,
    623 					    xml_node_t *parent,
    624 					    const char *user, const char *pw)
    625 {
    626 	xml_node_t *node;
    627 	char *b64;
    628 	size_t len;
    629 
    630 	node = xml_node_create(ctx->xml, parent, NULL, "UsernamePassword");
    631 	if (node == NULL)
    632 		return NULL;
    633 
    634 	add_text_node(ctx, node, "Username", user);
    635 
    636 	b64 = (char *) base64_encode((unsigned char *) pw, strlen(pw), NULL);
    637 	if (b64 == NULL)
    638 		return NULL;
    639 	len = os_strlen(b64);
    640 	if (len > 0 && b64[len - 1] == '\n')
    641 		b64[len - 1] = '\0';
    642 	add_text_node(ctx, node, "Password", b64);
    643 	free(b64);
    644 
    645 	return node;
    646 }
    647 
    648 
    649 static int add_username_password(struct hs20_svc *ctx, xml_node_t *cred,
    650 				 const char *user, const char *pw,
    651 				 int machine_managed)
    652 {
    653 	xml_node_t *node;
    654 
    655 	node = build_username_password(ctx, cred, user, pw);
    656 	if (node == NULL)
    657 		return -1;
    658 
    659 	add_text_node(ctx, node, "MachineManaged",
    660 		      machine_managed ? "TRUE" : "FALSE");
    661 	add_text_node(ctx, node, "SoftTokenApp", "");
    662 	add_eap_ttls(ctx, node);
    663 
    664 	return 0;
    665 }
    666 
    667 
    668 static void add_creation_date(struct hs20_svc *ctx, xml_node_t *cred)
    669 {
    670 	char str[30];
    671 	time_t now;
    672 	struct tm tm;
    673 
    674 	time(&now);
    675 	gmtime_r(&now, &tm);
    676 	snprintf(str, sizeof(str), "%04u-%02u-%02uT%02u:%02u:%02uZ",
    677 		 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
    678 		 tm.tm_hour, tm.tm_min, tm.tm_sec);
    679 	xml_node_create_text(ctx->xml, cred, NULL, "CreationDate", str);
    680 }
    681 
    682 
    683 static xml_node_t * build_credential_pw(struct hs20_svc *ctx,
    684 					const char *user, const char *realm,
    685 					const char *pw, int machine_managed)
    686 {
    687 	xml_node_t *cred;
    688 
    689 	cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential");
    690 	if (cred == NULL) {
    691 		debug_print(ctx, 1, "Failed to create Credential node");
    692 		return NULL;
    693 	}
    694 	add_creation_date(ctx, cred);
    695 	if (add_username_password(ctx, cred, user, pw, machine_managed) < 0) {
    696 		xml_node_free(ctx->xml, cred);
    697 		return NULL;
    698 	}
    699 	add_text_node(ctx, cred, "Realm", realm);
    700 
    701 	return cred;
    702 }
    703 
    704 
    705 static xml_node_t * build_credential(struct hs20_svc *ctx,
    706 				     const char *user, const char *realm,
    707 				     char *new_pw, size_t new_pw_len)
    708 {
    709 	if (new_password(new_pw, new_pw_len) < 0)
    710 		return NULL;
    711 	debug_print(ctx, 1, "Update password to '%s'", new_pw);
    712 	return build_credential_pw(ctx, user, realm, new_pw, 1);
    713 }
    714 
    715 
    716 static xml_node_t * build_credential_cert(struct hs20_svc *ctx,
    717 					  const char *user, const char *realm,
    718 					  const char *cert_fingerprint)
    719 {
    720 	xml_node_t *cred, *cert;
    721 
    722 	cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential");
    723 	if (cred == NULL) {
    724 		debug_print(ctx, 1, "Failed to create Credential node");
    725 		return NULL;
    726 	}
    727 	add_creation_date(ctx, cred);
    728 	cert = xml_node_create(ctx->xml, cred, NULL, "DigitalCertificate");
    729 	add_text_node(ctx, cert, "CertificateType", "x509v3");
    730 	add_text_node(ctx, cert, "CertSHA256Fingerprint", cert_fingerprint);
    731 	add_text_node(ctx, cred, "Realm", realm);
    732 
    733 	return cred;
    734 }
    735 
    736 
    737 static xml_node_t * build_post_dev_data_response(struct hs20_svc *ctx,
    738 						 xml_namespace_t **ret_ns,
    739 						 const char *session_id,
    740 						 const char *status,
    741 						 const char *error_code)
    742 {
    743 	xml_node_t *spp_node = NULL;
    744 	xml_namespace_t *ns;
    745 
    746 	spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
    747 					"sppPostDevDataResponse");
    748 	if (spp_node == NULL)
    749 		return NULL;
    750 	if (ret_ns)
    751 		*ret_ns = ns;
    752 
    753 	xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
    754 	xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
    755 	xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
    756 
    757 	if (error_code) {
    758 		xml_node_t *node;
    759 		node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
    760 		if (node)
    761 			xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
    762 					  error_code);
    763 	}
    764 
    765 	return spp_node;
    766 }
    767 
    768 
    769 static int add_update_node(struct hs20_svc *ctx, xml_node_t *spp_node,
    770 			   xml_namespace_t *ns, const char *uri,
    771 			   xml_node_t *upd_node)
    772 {
    773 	xml_node_t *node, *tnds;
    774 	char *str;
    775 
    776 	tnds = mo_to_tnds(ctx->xml, upd_node, 0, NULL, NULL);
    777 	if (!tnds)
    778 		return -1;
    779 
    780 	str = xml_node_to_str(ctx->xml, tnds);
    781 	xml_node_free(ctx->xml, tnds);
    782 	if (str == NULL)
    783 		return -1;
    784 	node = xml_node_create_text(ctx->xml, spp_node, ns, "updateNode", str);
    785 	free(str);
    786 
    787 	xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", uri);
    788 
    789 	return 0;
    790 }
    791 
    792 
    793 static xml_node_t * read_subrem_file(struct hs20_svc *ctx,
    794 				     const char *subrem_id,
    795 				     char *uri, size_t uri_size)
    796 {
    797 	char fname[200];
    798 	char *buf, *buf2, *pos;
    799 	size_t len;
    800 	xml_node_t *node;
    801 
    802 	os_snprintf(fname, sizeof(fname), "%s/spp/subrem/%s",
    803 		    ctx->root_dir, subrem_id);
    804 	debug_print(ctx, 1, "Use subrem file %s", fname);
    805 
    806 	buf = os_readfile(fname, &len);
    807 	if (!buf)
    808 		return NULL;
    809 	buf2 = os_realloc(buf, len + 1);
    810 	if (!buf2) {
    811 		os_free(buf);
    812 		return NULL;
    813 	}
    814 	buf = buf2;
    815 	buf[len] = '\0';
    816 
    817 	pos = os_strchr(buf, '\n');
    818 	if (!pos) {
    819 		os_free(buf);
    820 		return NULL;
    821 	}
    822 	*pos++ = '\0';
    823 	os_strlcpy(uri, buf, uri_size);
    824 
    825 	node = xml_node_from_buf(ctx->xml, pos);
    826 	os_free(buf);
    827 
    828 	return node;
    829 }
    830 
    831 
    832 static xml_node_t * build_sub_rem_resp(struct hs20_svc *ctx,
    833 				       const char *user, const char *realm,
    834 				       const char *session_id,
    835 				       int machine_rem, int dmacc)
    836 {
    837 	xml_namespace_t *ns;
    838 	xml_node_t *spp_node, *cred;
    839 	char buf[400];
    840 	char new_pw[33];
    841 	char *status;
    842 	char *cert;
    843 
    844 	cert = db_get_val(ctx, user, realm, "cert", dmacc);
    845 	if (cert && cert[0] == '\0') {
    846 		os_free(cert);
    847 		cert = NULL;
    848 	}
    849 	if (cert) {
    850 		char *subrem;
    851 
    852 		/* No change needed in PPS MO unless specifically asked to */
    853 		cred = NULL;
    854 		buf[0] = '\0';
    855 
    856 		subrem = db_get_val(ctx, user, realm, "subrem", dmacc);
    857 		if (subrem && subrem[0]) {
    858 			cred = read_subrem_file(ctx, subrem, buf, sizeof(buf));
    859 			if (!cred) {
    860 				debug_print(ctx, 1,
    861 					    "Could not create updateNode from subrem file");
    862 				os_free(subrem);
    863 				os_free(cert);
    864 				return NULL;
    865 			}
    866 		}
    867 		os_free(subrem);
    868 	} else {
    869 		char *real_user = NULL;
    870 		char *pw;
    871 
    872 		if (dmacc) {
    873 			real_user = db_get_val(ctx, user, realm, "identity",
    874 					       dmacc);
    875 			if (!real_user) {
    876 				debug_print(ctx, 1,
    877 					    "Could not find user identity for dmacc user '%s'",
    878 					    user);
    879 				return NULL;
    880 			}
    881 		}
    882 
    883 		pw = db_get_session_val(ctx, user, realm, session_id,
    884 					"password");
    885 		if (pw && pw[0]) {
    886 			debug_print(ctx, 1, "New password from the user: '%s'",
    887 				    pw);
    888 			snprintf(new_pw, sizeof(new_pw), "%s", pw);
    889 			free(pw);
    890 			cred = build_credential_pw(ctx,
    891 						   real_user ? real_user : user,
    892 						   realm, new_pw, 0);
    893 		} else {
    894 			cred = build_credential(ctx,
    895 						real_user ? real_user : user,
    896 						realm, new_pw, sizeof(new_pw));
    897 		}
    898 
    899 		free(real_user);
    900 		if (!cred) {
    901 			debug_print(ctx, 1, "Could not build credential");
    902 			os_free(cert);
    903 			return NULL;
    904 		}
    905 
    906 		snprintf(buf, sizeof(buf),
    907 			 "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
    908 			 realm);
    909 	}
    910 
    911 	status = "Remediation complete, request sppUpdateResponse";
    912 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
    913 						NULL);
    914 	if (spp_node == NULL) {
    915 		debug_print(ctx, 1, "Could not build sppPostDevDataResponse");
    916 		os_free(cert);
    917 		return NULL;
    918 	}
    919 
    920 	if ((cred && add_update_node(ctx, spp_node, ns, buf, cred) < 0) ||
    921 	    (!cred && !xml_node_create(ctx->xml, spp_node, ns, "noMOUpdate"))) {
    922 		debug_print(ctx, 1, "Could not add update node");
    923 		xml_node_free(ctx->xml, spp_node);
    924 		os_free(cert);
    925 		return NULL;
    926 	}
    927 
    928 	hs20_eventlog_node(ctx, user, realm, session_id,
    929 			   machine_rem ? "machine remediation" :
    930 			   "user remediation", cred);
    931 	xml_node_free(ctx->xml, cred);
    932 
    933 	if (cert) {
    934 		debug_print(ctx, 1, "Request DB remediation clearing on success notification (certificate credential)");
    935 		db_add_session(ctx, user, realm, session_id, NULL, NULL,
    936 			       CLEAR_REMEDIATION, NULL);
    937 	} else {
    938 		debug_print(ctx, 1, "Request DB password update on success "
    939 			    "notification");
    940 		db_add_session(ctx, user, realm, session_id, new_pw, NULL,
    941 			       UPDATE_PASSWORD, NULL);
    942 	}
    943 	os_free(cert);
    944 
    945 	return spp_node;
    946 }
    947 
    948 
    949 static xml_node_t * machine_remediation(struct hs20_svc *ctx,
    950 					const char *user,
    951 					const char *realm,
    952 					const char *session_id, int dmacc)
    953 {
    954 	return build_sub_rem_resp(ctx, user, realm, session_id, 1, dmacc);
    955 }
    956 
    957 
    958 static xml_node_t * cert_reenroll(struct hs20_svc *ctx,
    959 				  const char *user,
    960 				  const char *realm,
    961 				  const char *session_id)
    962 {
    963 	db_add_session(ctx, user, realm, session_id, NULL, NULL,
    964 		       CERT_REENROLL, NULL);
    965 	return spp_exec_get_certificate(ctx, session_id, user, realm, 0);
    966 }
    967 
    968 
    969 static xml_node_t * policy_remediation(struct hs20_svc *ctx,
    970 				       const char *user, const char *realm,
    971 				       const char *session_id, int dmacc)
    972 {
    973 	xml_namespace_t *ns;
    974 	xml_node_t *spp_node, *policy;
    975 	char buf[400];
    976 	const char *status;
    977 
    978 	hs20_eventlog(ctx, user, realm, session_id,
    979 		      "requires policy remediation", NULL);
    980 
    981 	db_add_session(ctx, user, realm, session_id, NULL, NULL,
    982 		       POLICY_REMEDIATION, NULL);
    983 
    984 	policy = build_policy(ctx, user, realm, dmacc);
    985 	if (!policy) {
    986 		return build_post_dev_data_response(
    987 			ctx, NULL, session_id,
    988 			"No update available at this time", NULL);
    989 	}
    990 
    991 	status = "Remediation complete, request sppUpdateResponse";
    992 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
    993 						NULL);
    994 	if (spp_node == NULL)
    995 		return NULL;
    996 
    997 	snprintf(buf, sizeof(buf),
    998 		 "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy",
    999 		 realm);
   1000 
   1001 	if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
   1002 		xml_node_free(ctx->xml, spp_node);
   1003 		xml_node_free(ctx->xml, policy);
   1004 		return NULL;
   1005 	}
   1006 
   1007 	hs20_eventlog_node(ctx, user, realm, session_id,
   1008 			   "policy update (sub rem)", policy);
   1009 	xml_node_free(ctx->xml, policy);
   1010 
   1011 	return spp_node;
   1012 }
   1013 
   1014 
   1015 static xml_node_t * browser_remediation(struct hs20_svc *ctx,
   1016 					const char *session_id,
   1017 					const char *redirect_uri,
   1018 					const char *uri)
   1019 {
   1020 	xml_namespace_t *ns;
   1021 	xml_node_t *spp_node, *exec_node;
   1022 
   1023 	if (redirect_uri == NULL) {
   1024 		debug_print(ctx, 1, "Missing redirectURI attribute for user "
   1025 			    "remediation");
   1026 		return NULL;
   1027 	}
   1028 	debug_print(ctx, 1, "redirectURI %s", redirect_uri);
   1029 
   1030 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
   1031 		NULL);
   1032 	if (spp_node == NULL)
   1033 		return NULL;
   1034 
   1035 	exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
   1036 	xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI",
   1037 			     uri);
   1038 	return spp_node;
   1039 }
   1040 
   1041 
   1042 static xml_node_t * user_remediation(struct hs20_svc *ctx, const char *user,
   1043 				     const char *realm, const char *session_id,
   1044 				     const char *redirect_uri)
   1045 {
   1046 	char uri[300], *val;
   1047 
   1048 	hs20_eventlog(ctx, user, realm, session_id,
   1049 		      "requires user remediation", NULL);
   1050 	val = db_get_osu_config_val(ctx, realm, "remediation_url");
   1051 	if (val == NULL)
   1052 		return NULL;
   1053 
   1054 	db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
   1055 		       USER_REMEDIATION, NULL);
   1056 
   1057 	snprintf(uri, sizeof(uri), "%s%s", val, session_id);
   1058 	os_free(val);
   1059 	return browser_remediation(ctx, session_id, redirect_uri, uri);
   1060 }
   1061 
   1062 
   1063 static xml_node_t * free_remediation(struct hs20_svc *ctx,
   1064 				     const char *user, const char *realm,
   1065 				     const char *session_id,
   1066 				     const char *redirect_uri)
   1067 {
   1068 	char uri[300], *val;
   1069 
   1070 	hs20_eventlog(ctx, user, realm, session_id,
   1071 		      "requires free/public account remediation", NULL);
   1072 	val = db_get_osu_config_val(ctx, realm, "free_remediation_url");
   1073 	if (val == NULL)
   1074 		return NULL;
   1075 
   1076 	db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
   1077 		       FREE_REMEDIATION, NULL);
   1078 
   1079 	snprintf(uri, sizeof(uri), "%s%s", val, session_id);
   1080 	os_free(val);
   1081 	return browser_remediation(ctx, session_id, redirect_uri, uri);
   1082 }
   1083 
   1084 
   1085 static xml_node_t * no_sub_rem(struct hs20_svc *ctx,
   1086 			       const char *user, const char *realm,
   1087 			       const char *session_id)
   1088 {
   1089 	const char *status;
   1090 
   1091 	hs20_eventlog(ctx, user, realm, session_id,
   1092 		      "no subscription mediation available", NULL);
   1093 
   1094 	status = "No update available at this time";
   1095 	return build_post_dev_data_response(ctx, NULL, session_id, status,
   1096 					    NULL);
   1097 }
   1098 
   1099 
   1100 static xml_node_t * hs20_subscription_remediation(struct hs20_svc *ctx,
   1101 						  const char *user,
   1102 						  const char *realm,
   1103 						  const char *session_id,
   1104 						  int dmacc,
   1105 						  const char *redirect_uri)
   1106 {
   1107 	char *type, *identity;
   1108 	xml_node_t *ret;
   1109 	char *free_account;
   1110 
   1111 	identity = db_get_val(ctx, user, realm, "identity", dmacc);
   1112 	if (identity == NULL || strlen(identity) == 0) {
   1113 		hs20_eventlog(ctx, user, realm, session_id,
   1114 			      "user not found in database for remediation",
   1115 			      NULL);
   1116 		os_free(identity);
   1117 		return build_post_dev_data_response(ctx, NULL, session_id,
   1118 						    "Error occurred",
   1119 						    "Not found");
   1120 	}
   1121 	os_free(identity);
   1122 
   1123 	free_account = db_get_osu_config_val(ctx, realm, "free_account");
   1124 	if (free_account && strcmp(free_account, user) == 0) {
   1125 		free(free_account);
   1126 		return no_sub_rem(ctx, user, realm, session_id);
   1127 	}
   1128 	free(free_account);
   1129 
   1130 	type = db_get_val(ctx, user, realm, "remediation", dmacc);
   1131 	if (type && strcmp(type, "free") != 0) {
   1132 		char *val;
   1133 		int shared = 0;
   1134 		val = db_get_val(ctx, user, realm, "shared", dmacc);
   1135 		if (val)
   1136 			shared = atoi(val);
   1137 		free(val);
   1138 		if (shared) {
   1139 			free(type);
   1140 			return no_sub_rem(ctx, user, realm, session_id);
   1141 		}
   1142 	}
   1143 	if (type && strcmp(type, "user") == 0)
   1144 		ret = user_remediation(ctx, user, realm, session_id,
   1145 				       redirect_uri);
   1146 	else if (type && strcmp(type, "free") == 0)
   1147 		ret = free_remediation(ctx, user, realm, session_id,
   1148 				       redirect_uri);
   1149 	else if (type && strcmp(type, "policy") == 0)
   1150 		ret = policy_remediation(ctx, user, realm, session_id, dmacc);
   1151 	else if (type && strcmp(type, "machine") == 0)
   1152 		ret = machine_remediation(ctx, user, realm, session_id, dmacc);
   1153 	else if (type && strcmp(type, "reenroll") == 0)
   1154 		ret = cert_reenroll(ctx, user, realm, session_id);
   1155 	else
   1156 		ret = no_sub_rem(ctx, user, realm, session_id);
   1157 	free(type);
   1158 
   1159 	return ret;
   1160 }
   1161 
   1162 
   1163 static xml_node_t * read_policy_file(struct hs20_svc *ctx,
   1164 				     const char *policy_id)
   1165 {
   1166 	char fname[200];
   1167 
   1168 	snprintf(fname, sizeof(fname), "%s/spp/policy/%s.xml",
   1169 		 ctx->root_dir, policy_id);
   1170 	debug_print(ctx, 1, "Use policy file %s", fname);
   1171 
   1172 	return node_from_file(ctx->xml, fname);
   1173 }
   1174 
   1175 
   1176 static void update_policy_update_uri(struct hs20_svc *ctx, const char *realm,
   1177 				     xml_node_t *policy)
   1178 {
   1179 	xml_node_t *node;
   1180 	char *url;
   1181 
   1182 	node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate/URI");
   1183 	if (!node)
   1184 		return;
   1185 
   1186 	url = db_get_osu_config_val(ctx, realm, "policy_url");
   1187 	if (!url)
   1188 		return;
   1189 	xml_node_set_text(ctx->xml, node, url);
   1190 	free(url);
   1191 }
   1192 
   1193 
   1194 static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
   1195 				 const char *realm, int use_dmacc)
   1196 {
   1197 	char *policy_id;
   1198 	xml_node_t *policy, *node;
   1199 
   1200 	policy_id = db_get_val(ctx, user, realm, "policy", use_dmacc);
   1201 	if (policy_id == NULL || strlen(policy_id) == 0) {
   1202 		free(policy_id);
   1203 		policy_id = strdup("default");
   1204 		if (policy_id == NULL)
   1205 			return NULL;
   1206 	}
   1207 	policy = read_policy_file(ctx, policy_id);
   1208 	free(policy_id);
   1209 	if (policy == NULL)
   1210 		return NULL;
   1211 
   1212 	update_policy_update_uri(ctx, realm, policy);
   1213 
   1214 	node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate");
   1215 	if (node && use_dmacc) {
   1216 		char *pw;
   1217 		pw = db_get_val(ctx, user, realm, "osu_password", use_dmacc);
   1218 		if (pw == NULL ||
   1219 		    build_username_password(ctx, node, user, pw) == NULL) {
   1220 			debug_print(ctx, 1, "Failed to add Policy/PolicyUpdate/"
   1221 				    "UsernamePassword");
   1222 			free(pw);
   1223 			xml_node_free(ctx->xml, policy);
   1224 			return NULL;
   1225 		}
   1226 		free(pw);
   1227 	}
   1228 
   1229 	return policy;
   1230 }
   1231 
   1232 
   1233 static xml_node_t * hs20_policy_update(struct hs20_svc *ctx,
   1234 				       const char *user, const char *realm,
   1235 				       const char *session_id, int dmacc)
   1236 {
   1237 	xml_namespace_t *ns;
   1238 	xml_node_t *spp_node;
   1239 	xml_node_t *policy;
   1240 	char buf[400];
   1241 	const char *status;
   1242 	char *identity;
   1243 
   1244 	identity = db_get_val(ctx, user, realm, "identity", dmacc);
   1245 	if (identity == NULL || strlen(identity) == 0) {
   1246 		hs20_eventlog(ctx, user, realm, session_id,
   1247 			      "user not found in database for policy update",
   1248 			      NULL);
   1249 		os_free(identity);
   1250 		return build_post_dev_data_response(ctx, NULL, session_id,
   1251 						    "Error occurred",
   1252 						    "Not found");
   1253 	}
   1254 	os_free(identity);
   1255 
   1256 	policy = build_policy(ctx, user, realm, dmacc);
   1257 	if (!policy) {
   1258 		return build_post_dev_data_response(
   1259 			ctx, NULL, session_id,
   1260 			"No update available at this time", NULL);
   1261 	}
   1262 
   1263 	db_add_session(ctx, user, realm, session_id, NULL, NULL, POLICY_UPDATE,
   1264 		       NULL);
   1265 
   1266 	status = "Update complete, request sppUpdateResponse";
   1267 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
   1268 						NULL);
   1269 	if (spp_node == NULL)
   1270 		return NULL;
   1271 
   1272 	snprintf(buf, sizeof(buf),
   1273 		 "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy",
   1274 		 realm);
   1275 
   1276 	if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
   1277 		xml_node_free(ctx->xml, spp_node);
   1278 		xml_node_free(ctx->xml, policy);
   1279 		return NULL;
   1280 	}
   1281 
   1282 	hs20_eventlog_node(ctx, user, realm, session_id, "policy update",
   1283 			   policy);
   1284 	xml_node_free(ctx->xml, policy);
   1285 
   1286 	return spp_node;
   1287 }
   1288 
   1289 
   1290 static xml_node_t * spp_get_mo(struct hs20_svc *ctx, xml_node_t *node,
   1291 			       const char *urn, int *valid, char **ret_err)
   1292 {
   1293 	xml_node_t *child, *tnds, *mo;
   1294 	const char *name;
   1295 	char *mo_urn;
   1296 	char *str;
   1297 	char fname[200];
   1298 
   1299 	*valid = -1;
   1300 	if (ret_err)
   1301 		*ret_err = NULL;
   1302 
   1303 	xml_node_for_each_child(ctx->xml, child, node) {
   1304 		xml_node_for_each_check(ctx->xml, child);
   1305 		name = xml_node_get_localname(ctx->xml, child);
   1306 		if (strcmp(name, "moContainer") != 0)
   1307 			continue;
   1308 		mo_urn = xml_node_get_attr_value_ns(ctx->xml, child, SPP_NS_URI,
   1309 						    "moURN");
   1310 		if (strcasecmp(urn, mo_urn) == 0) {
   1311 			xml_node_get_attr_value_free(ctx->xml, mo_urn);
   1312 			break;
   1313 		}
   1314 		xml_node_get_attr_value_free(ctx->xml, mo_urn);
   1315 	}
   1316 
   1317 	if (child == NULL)
   1318 		return NULL;
   1319 
   1320 	debug_print(ctx, 1, "moContainer text for %s", urn);
   1321 	debug_dump_node(ctx, "moContainer", child);
   1322 
   1323 	str = xml_node_get_text(ctx->xml, child);
   1324 	debug_print(ctx, 1, "moContainer payload: '%s'", str);
   1325 	tnds = xml_node_from_buf(ctx->xml, str);
   1326 	xml_node_get_text_free(ctx->xml, str);
   1327 	if (tnds == NULL) {
   1328 		debug_print(ctx, 1, "could not parse moContainer text");
   1329 		return NULL;
   1330 	}
   1331 
   1332 	snprintf(fname, sizeof(fname), "%s/spp/dm_ddf-v1_2.dtd", ctx->root_dir);
   1333 	if (xml_validate_dtd(ctx->xml, tnds, fname, ret_err) == 0)
   1334 		*valid = 1;
   1335 	else if (ret_err && *ret_err &&
   1336 		 os_strcmp(*ret_err, "No declaration for attribute xmlns of element MgmtTree\n") == 0) {
   1337 		free(*ret_err);
   1338 		debug_print(ctx, 1, "Ignore OMA-DM DDF DTD validation error for MgmtTree namespace declaration with xmlns attribute");
   1339 		*ret_err = NULL;
   1340 		*valid = 1;
   1341 	} else
   1342 		*valid = 0;
   1343 
   1344 	mo = tnds_to_mo(ctx->xml, tnds);
   1345 	xml_node_free(ctx->xml, tnds);
   1346 	if (mo == NULL) {
   1347 		debug_print(ctx, 1, "invalid moContainer for %s", urn);
   1348 	}
   1349 
   1350 	return mo;
   1351 }
   1352 
   1353 
   1354 static xml_node_t * spp_exec_upload_mo(struct hs20_svc *ctx,
   1355 				       const char *session_id, const char *urn)
   1356 {
   1357 	xml_namespace_t *ns;
   1358 	xml_node_t *spp_node, *node, *exec_node;
   1359 
   1360 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
   1361 						NULL);
   1362 	if (spp_node == NULL)
   1363 		return NULL;
   1364 
   1365 	exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
   1366 
   1367 	node = xml_node_create(ctx->xml, exec_node, ns, "uploadMO");
   1368 	xml_node_add_attr(ctx->xml, node, ns, "moURN", urn);
   1369 
   1370 	return spp_node;
   1371 }
   1372 
   1373 
   1374 static xml_node_t * hs20_subscription_registration(struct hs20_svc *ctx,
   1375 						   const char *realm,
   1376 						   const char *session_id,
   1377 						   const char *redirect_uri,
   1378 						   const u8 *mac_addr)
   1379 {
   1380 	xml_namespace_t *ns;
   1381 	xml_node_t *spp_node, *exec_node;
   1382 	char uri[300], *val;
   1383 
   1384 	if (db_add_session(ctx, NULL, realm, session_id, NULL, redirect_uri,
   1385 			   SUBSCRIPTION_REGISTRATION, mac_addr) < 0)
   1386 		return NULL;
   1387 	val = db_get_osu_config_val(ctx, realm, "signup_url");
   1388 	if (val == NULL)
   1389 		return NULL;
   1390 
   1391 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
   1392 						NULL);
   1393 	if (spp_node == NULL)
   1394 		return NULL;
   1395 
   1396 	exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
   1397 
   1398 	snprintf(uri, sizeof(uri), "%s%s", val, session_id);
   1399 	os_free(val);
   1400 	xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI",
   1401 			     uri);
   1402 	return spp_node;
   1403 }
   1404 
   1405 
   1406 static xml_node_t * hs20_user_input_remediation(struct hs20_svc *ctx,
   1407 						const char *user,
   1408 						const char *realm, int dmacc,
   1409 						const char *session_id)
   1410 {
   1411 	return build_sub_rem_resp(ctx, user, realm, session_id, 0, dmacc);
   1412 }
   1413 
   1414 
   1415 static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm,
   1416 				    const char *field)
   1417 {
   1418 	char *cmd;
   1419 	struct get_db_field_data data;
   1420 
   1421 	cmd = sqlite3_mprintf("SELECT value FROM osu_config WHERE realm=%Q AND "
   1422 			      "field=%Q", realm, field);
   1423 	if (cmd == NULL)
   1424 		return NULL;
   1425 	debug_print(ctx, 1, "DB: %s", cmd);
   1426 	memset(&data, 0, sizeof(data));
   1427 	data.field = "value";
   1428 	if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
   1429 	{
   1430 		debug_print(ctx, 1, "DB: Could not find osu_config %s: %s",
   1431 			    realm, sqlite3_errmsg(ctx->db));
   1432 		sqlite3_free(cmd);
   1433 		return NULL;
   1434 	}
   1435 	sqlite3_free(cmd);
   1436 
   1437 	debug_print(ctx, 1, "DB: return '%s'", data.value);
   1438 	return data.value;
   1439 }
   1440 
   1441 
   1442 static xml_node_t * build_pps(struct hs20_svc *ctx,
   1443 			      const char *user, const char *realm,
   1444 			      const char *pw, const char *cert,
   1445 			      int machine_managed, const char *test,
   1446 			      const char *imsi, const char *dmacc_username,
   1447 			      const char *dmacc_password,
   1448 			      xml_node_t *policy_node)
   1449 {
   1450 	xml_node_t *pps, *c, *trust, *aaa, *aaa1, *upd, *homesp, *p;
   1451 	xml_node_t *cred, *eap, *userpw;
   1452 
   1453 	pps = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
   1454 				   "PerProviderSubscription");
   1455 	if (!pps) {
   1456 		xml_node_free(ctx->xml, policy_node);
   1457 		return NULL;
   1458 	}
   1459 
   1460 	add_text_node(ctx, pps, "UpdateIdentifier", "1");
   1461 
   1462 	c = xml_node_create(ctx->xml, pps, NULL, "Cred01");
   1463 
   1464 	add_text_node(ctx, c, "CredentialPriority", "1");
   1465 
   1466 	if (imsi)
   1467 		goto skip_aaa_trust_root;
   1468 	aaa = xml_node_create(ctx->xml, c, NULL, "AAAServerTrustRoot");
   1469 	aaa1 = xml_node_create(ctx->xml, aaa, NULL, "AAA1");
   1470 	add_text_node_conf(ctx, realm, aaa1, "CertURL",
   1471 			   "aaa_trust_root_cert_url");
   1472 	if (test && os_strcmp(test, "corrupt_aaa_hash") == 0) {
   1473 		debug_print(ctx, 1,
   1474 			    "TEST: Corrupt PPS/Cred*/AAAServerTrustRoot/Root*/CertSHA256FingerPrint");
   1475 		add_text_node_conf_corrupt(ctx, realm, aaa1,
   1476 					   "CertSHA256Fingerprint",
   1477 					   "aaa_trust_root_cert_fingerprint");
   1478 	} else {
   1479 		add_text_node_conf(ctx, realm, aaa1, "CertSHA256Fingerprint",
   1480 				   "aaa_trust_root_cert_fingerprint");
   1481 	}
   1482 
   1483 	if (test && os_strcmp(test, "corrupt_polupd_hash") == 0) {
   1484 		debug_print(ctx, 1,
   1485 			    "TEST: Corrupt PPS/Cred*/Policy/PolicyUpdate/Trustroot/CertSHA256FingerPrint");
   1486 		p = xml_node_create(ctx->xml, c, NULL, "Policy");
   1487 		upd = xml_node_create(ctx->xml, p, NULL, "PolicyUpdate");
   1488 		add_text_node(ctx, upd, "UpdateInterval", "30");
   1489 		add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated");
   1490 		add_text_node(ctx, upd, "Restriction", "Unrestricted");
   1491 		add_text_node_conf(ctx, realm, upd, "URI", "policy_url");
   1492 		trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
   1493 		add_text_node_conf(ctx, realm, trust, "CertURL",
   1494 				   "policy_trust_root_cert_url");
   1495 		add_text_node_conf_corrupt(ctx, realm, trust,
   1496 					   "CertSHA256Fingerprint",
   1497 					   "policy_trust_root_cert_fingerprint");
   1498 	}
   1499 skip_aaa_trust_root:
   1500 
   1501 	upd = xml_node_create(ctx->xml, c, NULL, "SubscriptionUpdate");
   1502 	add_text_node(ctx, upd, "UpdateInterval", "4294967295");
   1503 	add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated");
   1504 	add_text_node(ctx, upd, "Restriction", "HomeSP");
   1505 	add_text_node_conf(ctx, realm, upd, "URI", "spp_http_auth_url");
   1506 	trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
   1507 	add_text_node_conf(ctx, realm, trust, "CertURL", "trust_root_cert_url");
   1508 	if (test && os_strcmp(test, "corrupt_subrem_hash") == 0) {
   1509 		debug_print(ctx, 1,
   1510 			    "TEST: Corrupt PPS/Cred*/SubscriptionUpdate/Trustroot/CertSHA256FingerPrint");
   1511 		add_text_node_conf_corrupt(ctx, realm, trust,
   1512 					   "CertSHA256Fingerprint",
   1513 					   "trust_root_cert_fingerprint");
   1514 	} else {
   1515 		add_text_node_conf(ctx, realm, trust, "CertSHA256Fingerprint",
   1516 				   "trust_root_cert_fingerprint");
   1517 	}
   1518 
   1519 	if (dmacc_username &&
   1520 	    !build_username_password(ctx, upd, dmacc_username,
   1521 				     dmacc_password)) {
   1522 		xml_node_free(ctx->xml, pps);
   1523 		xml_node_free(ctx->xml, policy_node);
   1524 		return NULL;
   1525 	}
   1526 
   1527 	if (policy_node)
   1528 		xml_node_add_child(ctx->xml, c, policy_node);
   1529 
   1530 	homesp = xml_node_create(ctx->xml, c, NULL, "HomeSP");
   1531 	add_text_node_conf(ctx, realm, homesp, "FriendlyName", "friendly_name");
   1532 	add_text_node_conf(ctx, realm, homesp, "FQDN", "fqdn");
   1533 
   1534 	xml_node_create(ctx->xml, c, NULL, "SubscriptionParameters");
   1535 
   1536 	cred = xml_node_create(ctx->xml, c, NULL, "Credential");
   1537 	add_creation_date(ctx, cred);
   1538 	if (imsi) {
   1539 		xml_node_t *sim;
   1540 		const char *type = "18"; /* default to EAP-SIM */
   1541 
   1542 		sim = xml_node_create(ctx->xml, cred, NULL, "SIM");
   1543 		add_text_node(ctx, sim, "IMSI", imsi);
   1544 		if (ctx->eap_method && os_strcmp(ctx->eap_method, "AKA") == 0)
   1545 			type = "23";
   1546 		else if (ctx->eap_method &&
   1547 			 os_strcmp(ctx->eap_method, "AKA'") == 0)
   1548 			type = "50";
   1549 		add_text_node(ctx, sim, "EAPType", type);
   1550 	} else if (cert) {
   1551 		xml_node_t *dc;
   1552 		dc = xml_node_create(ctx->xml, cred, NULL,
   1553 				     "DigitalCertificate");
   1554 		add_text_node(ctx, dc, "CertificateType", "x509v3");
   1555 		add_text_node(ctx, dc, "CertSHA256Fingerprint", cert);
   1556 	} else {
   1557 		userpw = build_username_password(ctx, cred, user, pw);
   1558 		add_text_node(ctx, userpw, "MachineManaged",
   1559 			      machine_managed ? "TRUE" : "FALSE");
   1560 		eap = xml_node_create(ctx->xml, userpw, NULL, "EAPMethod");
   1561 		add_text_node(ctx, eap, "EAPType", "21");
   1562 		add_text_node(ctx, eap, "InnerMethod", "MS-CHAP-V2");
   1563 	}
   1564 	add_text_node(ctx, cred, "Realm", realm);
   1565 
   1566 	return pps;
   1567 }
   1568 
   1569 
   1570 static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx,
   1571 					     const char *session_id,
   1572 					     const char *user,
   1573 					     const char *realm,
   1574 					     int add_est_user)
   1575 {
   1576 	xml_namespace_t *ns;
   1577 	xml_node_t *spp_node, *enroll, *exec_node;
   1578 	char *val;
   1579 	char password[11];
   1580 	char *b64;
   1581 
   1582 	if (add_est_user && new_password(password, sizeof(password)) < 0)
   1583 		return NULL;
   1584 
   1585 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
   1586 						NULL);
   1587 	if (spp_node == NULL)
   1588 		return NULL;
   1589 
   1590 	exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
   1591 
   1592 	enroll = xml_node_create(ctx->xml, exec_node, ns, "getCertificate");
   1593 	xml_node_add_attr(ctx->xml, enroll, NULL, "enrollmentProtocol", "EST");
   1594 
   1595 	val = db_get_osu_config_val(ctx, realm, "est_url");
   1596 	xml_node_create_text(ctx->xml, enroll, ns, "enrollmentServerURI",
   1597 			     val ? val : "");
   1598 	os_free(val);
   1599 
   1600 	if (!add_est_user)
   1601 		return spp_node;
   1602 
   1603 	xml_node_create_text(ctx->xml, enroll, ns, "estUserID", user);
   1604 
   1605 	b64 = (char *) base64_encode((unsigned char *) password,
   1606 				     strlen(password), NULL);
   1607 	if (b64 == NULL) {
   1608 		xml_node_free(ctx->xml, spp_node);
   1609 		return NULL;
   1610 	}
   1611 	xml_node_create_text(ctx->xml, enroll, ns, "estPassword", b64);
   1612 	free(b64);
   1613 
   1614 	db_update_session_password(ctx, user, realm, session_id, password);
   1615 
   1616 	return spp_node;
   1617 }
   1618 
   1619 
   1620 static xml_node_t * hs20_user_input_registration(struct hs20_svc *ctx,
   1621 						 const char *session_id,
   1622 						 int enrollment_done)
   1623 {
   1624 	xml_namespace_t *ns;
   1625 	xml_node_t *spp_node, *node = NULL;
   1626 	xml_node_t *pps, *tnds;
   1627 	char buf[400];
   1628 	char *str;
   1629 	char *user, *realm, *pw, *type, *mm, *test;
   1630 	const char *status;
   1631 	int cert = 0;
   1632 	int machine_managed = 0;
   1633 	char *fingerprint;
   1634 
   1635 	user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
   1636 	realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
   1637 	pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
   1638 
   1639 	if (!user || !realm || !pw) {
   1640 		debug_print(ctx, 1, "Could not find session info from DB for "
   1641 			    "the new subscription");
   1642 		free(user);
   1643 		free(realm);
   1644 		free(pw);
   1645 		return NULL;
   1646 	}
   1647 
   1648 	mm = db_get_session_val(ctx, NULL, NULL, session_id, "machine_managed");
   1649 	if (mm && atoi(mm))
   1650 		machine_managed = 1;
   1651 	free(mm);
   1652 
   1653 	type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
   1654 	if (type && strcmp(type, "cert") == 0)
   1655 		cert = 1;
   1656 	free(type);
   1657 
   1658 	if (cert && !enrollment_done) {
   1659 		xml_node_t *ret;
   1660 		hs20_eventlog(ctx, user, realm, session_id,
   1661 			      "request client certificate enrollment", NULL);
   1662 		ret = spp_exec_get_certificate(ctx, session_id, user, realm, 1);
   1663 		free(user);
   1664 		free(realm);
   1665 		free(pw);
   1666 		return ret;
   1667 	}
   1668 
   1669 	if (!cert && strlen(pw) == 0) {
   1670 		machine_managed = 1;
   1671 		free(pw);
   1672 		pw = malloc(11);
   1673 		if (pw == NULL || new_password(pw, 11) < 0) {
   1674 			free(user);
   1675 			free(realm);
   1676 			free(pw);
   1677 			return NULL;
   1678 		}
   1679 	}
   1680 
   1681 	status = "Provisioning complete, request sppUpdateResponse";
   1682 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
   1683 						NULL);
   1684 	if (spp_node == NULL)
   1685 		return NULL;
   1686 
   1687 	fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
   1688 	test = db_get_session_val(ctx, NULL, NULL, session_id, "test");
   1689 	if (test)
   1690 		debug_print(ctx, 1, "TEST: Requested special behavior: %s",
   1691 			    test);
   1692 	pps = build_pps(ctx, user, realm, pw,
   1693 			fingerprint ? fingerprint : NULL, machine_managed,
   1694 			test, NULL, NULL, NULL, NULL);
   1695 	free(fingerprint);
   1696 	free(test);
   1697 	if (!pps) {
   1698 		xml_node_free(ctx->xml, spp_node);
   1699 		free(user);
   1700 		free(realm);
   1701 		free(pw);
   1702 		return NULL;
   1703 	}
   1704 
   1705 	debug_print(ctx, 1, "Request DB subscription registration on success "
   1706 		    "notification");
   1707 	if (machine_managed) {
   1708 		db_update_session_password(ctx, user, realm, session_id, pw);
   1709 		db_update_session_machine_managed(ctx, user, realm, session_id,
   1710 						  machine_managed);
   1711 	}
   1712 	db_add_session_pps(ctx, user, realm, session_id, pps);
   1713 
   1714 	hs20_eventlog_node(ctx, user, realm, session_id,
   1715 			   "new subscription", pps);
   1716 	free(user);
   1717 	free(pw);
   1718 
   1719 	tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL);
   1720 	xml_node_free(ctx->xml, pps);
   1721 	if (!tnds) {
   1722 		xml_node_free(ctx->xml, spp_node);
   1723 		free(realm);
   1724 		return NULL;
   1725 	}
   1726 
   1727 	str = xml_node_to_str(ctx->xml, tnds);
   1728 	xml_node_free(ctx->xml, tnds);
   1729 	if (str == NULL) {
   1730 		xml_node_free(ctx->xml, spp_node);
   1731 		free(realm);
   1732 		return NULL;
   1733 	}
   1734 
   1735 	node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str);
   1736 	free(str);
   1737 	snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm);
   1738 	free(realm);
   1739 	xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf);
   1740 	xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS);
   1741 
   1742 	return spp_node;
   1743 }
   1744 
   1745 
   1746 static xml_node_t * hs20_user_input_free_remediation(struct hs20_svc *ctx,
   1747 						     const char *user,
   1748 						     const char *realm,
   1749 						     const char *session_id)
   1750 {
   1751 	xml_namespace_t *ns;
   1752 	xml_node_t *spp_node;
   1753 	xml_node_t *cred;
   1754 	char buf[400];
   1755 	char *status;
   1756 	char *free_account, *pw;
   1757 
   1758 	free_account = db_get_osu_config_val(ctx, realm, "free_account");
   1759 	if (free_account == NULL)
   1760 		return NULL;
   1761 	pw = db_get_val(ctx, free_account, realm, "password", 0);
   1762 	if (pw == NULL) {
   1763 		free(free_account);
   1764 		return NULL;
   1765 	}
   1766 
   1767 	cred = build_credential_pw(ctx, free_account, realm, pw, 1);
   1768 	free(free_account);
   1769 	free(pw);
   1770 	if (!cred) {
   1771 		xml_node_free(ctx->xml, cred);
   1772 		return NULL;
   1773 	}
   1774 
   1775 	status = "Remediation complete, request sppUpdateResponse";
   1776 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
   1777 						NULL);
   1778 	if (spp_node == NULL)
   1779 		return NULL;
   1780 
   1781 	snprintf(buf, sizeof(buf),
   1782 		 "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
   1783 		 realm);
   1784 
   1785 	if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
   1786 		xml_node_free(ctx->xml, spp_node);
   1787 		return NULL;
   1788 	}
   1789 
   1790 	hs20_eventlog_node(ctx, user, realm, session_id,
   1791 			   "free/public remediation", cred);
   1792 	xml_node_free(ctx->xml, cred);
   1793 
   1794 	return spp_node;
   1795 }
   1796 
   1797 
   1798 static xml_node_t * hs20_user_input_complete(struct hs20_svc *ctx,
   1799 					     const char *user,
   1800 					     const char *realm, int dmacc,
   1801 					     const char *session_id)
   1802 {
   1803 	char *val;
   1804 	enum hs20_session_operation oper;
   1805 
   1806 	val = db_get_session_val(ctx, user, realm, session_id, "operation");
   1807 	if (val == NULL) {
   1808 		debug_print(ctx, 1, "No session %s found to continue",
   1809 			    session_id);
   1810 		return NULL;
   1811 	}
   1812 	oper = atoi(val);
   1813 	free(val);
   1814 
   1815 	if (oper == USER_REMEDIATION) {
   1816 		return hs20_user_input_remediation(ctx, user, realm, dmacc,
   1817 						   session_id);
   1818 	}
   1819 
   1820 	if (oper == FREE_REMEDIATION) {
   1821 		return hs20_user_input_free_remediation(ctx, user, realm,
   1822 							session_id);
   1823 	}
   1824 
   1825 	if (oper == SUBSCRIPTION_REGISTRATION) {
   1826 		return hs20_user_input_registration(ctx, session_id, 0);
   1827 	}
   1828 
   1829 	debug_print(ctx, 1, "User session %s not in state for user input "
   1830 		    "completion", session_id);
   1831 	return NULL;
   1832 }
   1833 
   1834 
   1835 static xml_node_t * hs20_cert_reenroll_complete(struct hs20_svc *ctx,
   1836 						 const char *session_id)
   1837 {
   1838 	char *user, *realm, *cert;
   1839 	char *status;
   1840 	xml_namespace_t *ns;
   1841 	xml_node_t *spp_node, *cred;
   1842 	char buf[400];
   1843 
   1844 	user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
   1845 	realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
   1846 	cert = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
   1847 	if (!user || !realm || !cert) {
   1848 		debug_print(ctx, 1,
   1849 			    "Could not find session info from DB for certificate reenrollment");
   1850 		free(user);
   1851 		free(realm);
   1852 		free(cert);
   1853 		return NULL;
   1854 	}
   1855 
   1856 	cred = build_credential_cert(ctx, user, realm, cert);
   1857 	if (!cred) {
   1858 		debug_print(ctx, 1, "Could not build credential");
   1859 		free(user);
   1860 		free(realm);
   1861 		free(cert);
   1862 		return NULL;
   1863 	}
   1864 
   1865 	status = "Remediation complete, request sppUpdateResponse";
   1866 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
   1867 						NULL);
   1868 	if (spp_node == NULL) {
   1869 		debug_print(ctx, 1, "Could not build sppPostDevDataResponse");
   1870 		free(user);
   1871 		free(realm);
   1872 		free(cert);
   1873 		xml_node_free(ctx->xml, cred);
   1874 		return NULL;
   1875 	}
   1876 
   1877 	snprintf(buf, sizeof(buf),
   1878 		 "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
   1879 		 realm);
   1880 
   1881 	if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
   1882 		debug_print(ctx, 1, "Could not add update node");
   1883 		xml_node_free(ctx->xml, spp_node);
   1884 		free(user);
   1885 		free(realm);
   1886 		free(cert);
   1887 		return NULL;
   1888 	}
   1889 
   1890 	hs20_eventlog_node(ctx, user, realm, session_id,
   1891 			   "certificate reenrollment", cred);
   1892 	xml_node_free(ctx->xml, cred);
   1893 
   1894 	free(user);
   1895 	free(realm);
   1896 	free(cert);
   1897 	return spp_node;
   1898 }
   1899 
   1900 
   1901 static xml_node_t * hs20_cert_enroll_completed(struct hs20_svc *ctx,
   1902 					       const char *user,
   1903 					       const char *realm, int dmacc,
   1904 					       const char *session_id)
   1905 {
   1906 	char *val;
   1907 	enum hs20_session_operation oper;
   1908 
   1909 	val = db_get_session_val(ctx, NULL, NULL, session_id, "operation");
   1910 	if (val == NULL) {
   1911 		debug_print(ctx, 1, "No session %s found to continue",
   1912 			    session_id);
   1913 		return NULL;
   1914 	}
   1915 	oper = atoi(val);
   1916 	free(val);
   1917 
   1918 	if (oper == SUBSCRIPTION_REGISTRATION)
   1919 		return hs20_user_input_registration(ctx, session_id, 1);
   1920 	if (oper == CERT_REENROLL)
   1921 		return hs20_cert_reenroll_complete(ctx, session_id);
   1922 
   1923 	debug_print(ctx, 1, "User session %s not in state for certificate "
   1924 		    "enrollment completion", session_id);
   1925 	return NULL;
   1926 }
   1927 
   1928 
   1929 static xml_node_t * hs20_cert_enroll_failed(struct hs20_svc *ctx,
   1930 					    const char *user,
   1931 					    const char *realm, int dmacc,
   1932 					    const char *session_id)
   1933 {
   1934 	char *val;
   1935 	enum hs20_session_operation oper;
   1936 	xml_node_t *spp_node, *node;
   1937 	char *status;
   1938 	xml_namespace_t *ns;
   1939 
   1940 	val = db_get_session_val(ctx, user, realm, session_id, "operation");
   1941 	if (val == NULL) {
   1942 		debug_print(ctx, 1, "No session %s found to continue",
   1943 			    session_id);
   1944 		return NULL;
   1945 	}
   1946 	oper = atoi(val);
   1947 	free(val);
   1948 
   1949 	if (oper != SUBSCRIPTION_REGISTRATION) {
   1950 		debug_print(ctx, 1, "User session %s not in state for "
   1951 			    "enrollment failure", session_id);
   1952 		return NULL;
   1953 	}
   1954 
   1955 	status = "Error occurred";
   1956 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
   1957 						NULL);
   1958 	if (spp_node == NULL)
   1959 		return NULL;
   1960 	node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
   1961 	xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
   1962 			  "Credentials cannot be provisioned at this time");
   1963 	db_remove_session(ctx, user, realm, session_id);
   1964 
   1965 	return spp_node;
   1966 }
   1967 
   1968 
   1969 static xml_node_t * hs20_sim_provisioning(struct hs20_svc *ctx,
   1970 					  const char *user,
   1971 					  const char *realm, int dmacc,
   1972 					  const char *session_id)
   1973 {
   1974 	xml_namespace_t *ns;
   1975 	xml_node_t *spp_node, *node = NULL;
   1976 	xml_node_t *pps, *tnds;
   1977 	char buf[400];
   1978 	char *str;
   1979 	const char *status;
   1980 	char dmacc_username[32];
   1981 	char dmacc_password[32];
   1982 	char *policy;
   1983 	xml_node_t *policy_node = NULL;
   1984 
   1985 	if (!ctx->imsi) {
   1986 		debug_print(ctx, 1, "IMSI not available for SIM provisioning");
   1987 		return NULL;
   1988 	}
   1989 
   1990 	if (new_password(dmacc_username, sizeof(dmacc_username)) < 0 ||
   1991 	    new_password(dmacc_password, sizeof(dmacc_password)) < 0) {
   1992 		debug_print(ctx, 1,
   1993 			    "Failed to generate DMAcc username/password");
   1994 		return NULL;
   1995 	}
   1996 
   1997 	status = "Provisioning complete, request sppUpdateResponse";
   1998 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
   1999 						NULL);
   2000 	if (!spp_node)
   2001 		return NULL;
   2002 
   2003 	policy = db_get_osu_config_val(ctx, realm, "sim_policy");
   2004 	if (policy) {
   2005 		policy_node = read_policy_file(ctx, policy);
   2006 		os_free(policy);
   2007 		if (!policy_node) {
   2008 			xml_node_free(ctx->xml, spp_node);
   2009 			return NULL;
   2010 		}
   2011 		update_policy_update_uri(ctx, realm, policy_node);
   2012 		node = get_node_uri(ctx->xml, policy_node,
   2013 				    "Policy/PolicyUpdate");
   2014 		if (node)
   2015 			build_username_password(ctx, node, dmacc_username,
   2016 						dmacc_password);
   2017 	}
   2018 
   2019 	pps = build_pps(ctx, NULL, realm, NULL, NULL, 0, NULL, ctx->imsi,
   2020 			dmacc_username, dmacc_password, policy_node);
   2021 	if (!pps) {
   2022 		xml_node_free(ctx->xml, spp_node);
   2023 		return NULL;
   2024 	}
   2025 
   2026 	debug_print(ctx, 1,
   2027 		    "Request DB subscription registration on success notification");
   2028 	if (!user || !user[0])
   2029 		user = ctx->imsi;
   2030 	db_add_session(ctx, user, realm, session_id, NULL, NULL,
   2031 		       SUBSCRIPTION_REGISTRATION, NULL);
   2032 	db_add_session_dmacc(ctx, session_id, dmacc_username, dmacc_password);
   2033 	if (ctx->eap_method)
   2034 		db_add_session_eap_method(ctx, session_id, ctx->eap_method);
   2035 	if (ctx->id_hash)
   2036 		db_add_session_id_hash(ctx, session_id, ctx->id_hash);
   2037 	db_add_session_pps(ctx, user, realm, session_id, pps);
   2038 
   2039 	hs20_eventlog_node(ctx, user, realm, session_id,
   2040 			   "new subscription", pps);
   2041 
   2042 	tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL);
   2043 	xml_node_free(ctx->xml, pps);
   2044 	if (!tnds) {
   2045 		xml_node_free(ctx->xml, spp_node);
   2046 		return NULL;
   2047 	}
   2048 
   2049 	str = xml_node_to_str(ctx->xml, tnds);
   2050 	xml_node_free(ctx->xml, tnds);
   2051 	if (!str) {
   2052 		xml_node_free(ctx->xml, spp_node);
   2053 		return NULL;
   2054 	}
   2055 
   2056 	node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str);
   2057 	free(str);
   2058 	snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm);
   2059 	xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf);
   2060 	xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS);
   2061 
   2062 	return spp_node;
   2063 }
   2064 
   2065 
   2066 static xml_node_t * hs20_spp_post_dev_data(struct hs20_svc *ctx,
   2067 					   xml_node_t *node,
   2068 					   const char *user,
   2069 					   const char *realm,
   2070 					   const char *session_id,
   2071 					   int dmacc)
   2072 {
   2073 	const char *req_reason;
   2074 	char *redirect_uri = NULL;
   2075 	char *req_reason_buf = NULL;
   2076 	char str[200];
   2077 	xml_node_t *ret = NULL, *devinfo = NULL, *devdetail = NULL;
   2078 	xml_node_t *mo, *macaddr;
   2079 	char *version;
   2080 	int valid;
   2081 	char *supp, *pos;
   2082 	char *err;
   2083 	u8 wifi_mac_addr[ETH_ALEN];
   2084 
   2085 	version = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
   2086 					     "sppVersion");
   2087 	if (version == NULL || strstr(version, "1.0") == NULL) {
   2088 		ret = build_post_dev_data_response(
   2089 			ctx, NULL, session_id, "Error occurred",
   2090 			"SPP version not supported");
   2091 		hs20_eventlog_node(ctx, user, realm, session_id,
   2092 				   "Unsupported sppVersion", ret);
   2093 		xml_node_get_attr_value_free(ctx->xml, version);
   2094 		return ret;
   2095 	}
   2096 	xml_node_get_attr_value_free(ctx->xml, version);
   2097 
   2098 	mo = get_node(ctx->xml, node, "supportedMOList");
   2099 	if (mo == NULL) {
   2100 		ret = build_post_dev_data_response(
   2101 			ctx, NULL, session_id, "Error occurred",
   2102 			"Other");
   2103 		hs20_eventlog_node(ctx, user, realm, session_id,
   2104 				   "No supportedMOList element", ret);
   2105 		return ret;
   2106 	}
   2107 	supp = xml_node_get_text(ctx->xml, mo);
   2108 	for (pos = supp; pos && *pos; pos++)
   2109 		*pos = tolower(*pos);
   2110 	if (supp == NULL ||
   2111 	    strstr(supp, URN_OMA_DM_DEVINFO) == NULL ||
   2112 	    strstr(supp, URN_OMA_DM_DEVDETAIL) == NULL ||
   2113 	    strstr(supp, URN_HS20_PPS) == NULL) {
   2114 		xml_node_get_text_free(ctx->xml, supp);
   2115 		ret = build_post_dev_data_response(
   2116 			ctx, NULL, session_id, "Error occurred",
   2117 			"One or more mandatory MOs not supported");
   2118 		hs20_eventlog_node(ctx, user, realm, session_id,
   2119 				   "Unsupported MOs", ret);
   2120 		return ret;
   2121 	}
   2122 	xml_node_get_text_free(ctx->xml, supp);
   2123 
   2124 	req_reason_buf = xml_node_get_attr_value(ctx->xml, node,
   2125 						 "requestReason");
   2126 	if (req_reason_buf == NULL) {
   2127 		debug_print(ctx, 1, "No requestReason attribute");
   2128 		return NULL;
   2129 	}
   2130 	req_reason = req_reason_buf;
   2131 
   2132 	redirect_uri = xml_node_get_attr_value(ctx->xml, node, "redirectURI");
   2133 
   2134 	debug_print(ctx, 1, "requestReason: %s  sessionID: %s  redirectURI: %s",
   2135 		    req_reason, session_id, redirect_uri);
   2136 	snprintf(str, sizeof(str), "sppPostDevData: requestReason=%s",
   2137 		 req_reason);
   2138 	hs20_eventlog(ctx, user, realm, session_id, str, NULL);
   2139 
   2140 	devinfo = spp_get_mo(ctx, node, URN_OMA_DM_DEVINFO, &valid, &err);
   2141 	if (devinfo == NULL) {
   2142 		ret = build_post_dev_data_response(ctx, NULL, session_id,
   2143 						   "Error occurred", "Other");
   2144 		hs20_eventlog_node(ctx, user, realm, session_id,
   2145 				   "No DevInfo moContainer in sppPostDevData",
   2146 				   ret);
   2147 		os_free(err);
   2148 		goto out;
   2149 	}
   2150 
   2151 	hs20_eventlog_node(ctx, user, realm, session_id,
   2152 			   "Received DevInfo MO", devinfo);
   2153 	if (valid == 0) {
   2154 		hs20_eventlog(ctx, user, realm, session_id,
   2155 			      "OMA-DM DDF DTD validation errors in DevInfo MO",
   2156 			      err);
   2157 		ret = build_post_dev_data_response(ctx, NULL, session_id,
   2158 						   "Error occurred", "Other");
   2159 		os_free(err);
   2160 		goto out;
   2161 	}
   2162 	os_free(err);
   2163 	if (user)
   2164 		db_update_mo(ctx, user, realm, "devinfo", devinfo);
   2165 
   2166 	devdetail = spp_get_mo(ctx, node, URN_OMA_DM_DEVDETAIL, &valid, &err);
   2167 	if (devdetail == NULL) {
   2168 		ret = build_post_dev_data_response(ctx, NULL, session_id,
   2169 						   "Error occurred", "Other");
   2170 		hs20_eventlog_node(ctx, user, realm, session_id,
   2171 				   "No DevDetail moContainer in sppPostDevData",
   2172 				   ret);
   2173 		os_free(err);
   2174 		goto out;
   2175 	}
   2176 
   2177 	hs20_eventlog_node(ctx, user, realm, session_id,
   2178 			   "Received DevDetail MO", devdetail);
   2179 	if (valid == 0) {
   2180 		hs20_eventlog(ctx, user, realm, session_id,
   2181 			      "OMA-DM DDF DTD validation errors "
   2182 			      "in DevDetail MO", err);
   2183 		ret = build_post_dev_data_response(ctx, NULL, session_id,
   2184 						   "Error occurred", "Other");
   2185 		os_free(err);
   2186 		goto out;
   2187 	}
   2188 	os_free(err);
   2189 
   2190 	os_memset(wifi_mac_addr, 0, ETH_ALEN);
   2191 	macaddr = get_node(ctx->xml, devdetail,
   2192 			   "Ext/org.wi-fi/Wi-Fi/Wi-FiMACAddress");
   2193 	if (macaddr) {
   2194 		char *addr, buf[50];
   2195 
   2196 		addr = xml_node_get_text(ctx->xml, macaddr);
   2197 		if (addr && hwaddr_compact_aton(addr, wifi_mac_addr) == 0) {
   2198 			snprintf(buf, sizeof(buf), "DevDetail MAC address: "
   2199 				 MACSTR, MAC2STR(wifi_mac_addr));
   2200 			hs20_eventlog(ctx, user, realm, session_id, buf, NULL);
   2201 			xml_node_get_text_free(ctx->xml, addr);
   2202 		} else {
   2203 			hs20_eventlog(ctx, user, realm, session_id,
   2204 				      "Could not extract MAC address from DevDetail",
   2205 				      NULL);
   2206 		}
   2207 	} else {
   2208 		hs20_eventlog(ctx, user, realm, session_id,
   2209 			      "No MAC address in DevDetail", NULL);
   2210 	}
   2211 
   2212 	if (user)
   2213 		db_update_mo(ctx, user, realm, "devdetail", devdetail);
   2214 
   2215 	if (user)
   2216 		mo = spp_get_mo(ctx, node, URN_HS20_PPS, &valid, &err);
   2217 	else {
   2218 		mo = NULL;
   2219 		err = NULL;
   2220 	}
   2221 	if (user && mo) {
   2222 		hs20_eventlog_node(ctx, user, realm, session_id,
   2223 				   "Received PPS MO", mo);
   2224 		if (valid == 0) {
   2225 			hs20_eventlog(ctx, user, realm, session_id,
   2226 				      "OMA-DM DDF DTD validation errors "
   2227 				      "in PPS MO", err);
   2228 			xml_node_get_attr_value_free(ctx->xml, redirect_uri);
   2229 			os_free(err);
   2230 			return build_post_dev_data_response(
   2231 				ctx, NULL, session_id,
   2232 				"Error occurred", "Other");
   2233 		}
   2234 		db_update_mo(ctx, user, realm, "pps", mo);
   2235 		db_update_val(ctx, user, realm, "fetch_pps", "0", dmacc);
   2236 		xml_node_free(ctx->xml, mo);
   2237 	}
   2238 	os_free(err);
   2239 
   2240 	if (user && !mo) {
   2241 		char *fetch;
   2242 		int fetch_pps;
   2243 
   2244 		fetch = db_get_val(ctx, user, realm, "fetch_pps", dmacc);
   2245 		fetch_pps = fetch ? atoi(fetch) : 0;
   2246 		free(fetch);
   2247 
   2248 		if (fetch_pps) {
   2249 			enum hs20_session_operation oper;
   2250 			if (strcasecmp(req_reason, "Subscription remediation")
   2251 			    == 0)
   2252 				oper = CONTINUE_SUBSCRIPTION_REMEDIATION;
   2253 			else if (strcasecmp(req_reason, "Policy update") == 0)
   2254 				oper = CONTINUE_POLICY_UPDATE;
   2255 			else
   2256 				oper = NO_OPERATION;
   2257 			if (db_add_session(ctx, user, realm, session_id, NULL,
   2258 					   NULL, oper, NULL) < 0)
   2259 				goto out;
   2260 
   2261 			ret = spp_exec_upload_mo(ctx, session_id,
   2262 						 URN_HS20_PPS);
   2263 			hs20_eventlog_node(ctx, user, realm, session_id,
   2264 					   "request PPS MO upload",
   2265 					   ret);
   2266 			goto out;
   2267 		}
   2268 	}
   2269 
   2270 	if (user && strcasecmp(req_reason, "MO upload") == 0) {
   2271 		char *val = db_get_session_val(ctx, user, realm, session_id,
   2272 					       "operation");
   2273 		enum hs20_session_operation oper;
   2274 		if (!val) {
   2275 			debug_print(ctx, 1, "No session %s found to continue",
   2276 				    session_id);
   2277 			goto out;
   2278 		}
   2279 		oper = atoi(val);
   2280 		free(val);
   2281 		if (oper == CONTINUE_SUBSCRIPTION_REMEDIATION)
   2282 			req_reason = "Subscription remediation";
   2283 		else if (oper == CONTINUE_POLICY_UPDATE)
   2284 			req_reason = "Policy update";
   2285 		else {
   2286 			debug_print(ctx, 1,
   2287 				    "No pending operation in session %s",
   2288 				    session_id);
   2289 			goto out;
   2290 		}
   2291 	}
   2292 
   2293 	if (strcasecmp(req_reason, "Subscription registration") == 0) {
   2294 		ret = hs20_subscription_registration(ctx, realm, session_id,
   2295 						     redirect_uri,
   2296 						     wifi_mac_addr);
   2297 		hs20_eventlog_node(ctx, user, realm, session_id,
   2298 				   "subscription registration response",
   2299 				   ret);
   2300 		goto out;
   2301 	}
   2302 	if (user && strcasecmp(req_reason, "Subscription remediation") == 0) {
   2303 		ret = hs20_subscription_remediation(ctx, user, realm,
   2304 						    session_id, dmacc,
   2305 						    redirect_uri);
   2306 		hs20_eventlog_node(ctx, user, realm, session_id,
   2307 				   "subscription remediation response",
   2308 				   ret);
   2309 		goto out;
   2310 	}
   2311 	if (user && strcasecmp(req_reason, "Policy update") == 0) {
   2312 		ret = hs20_policy_update(ctx, user, realm, session_id, dmacc);
   2313 		hs20_eventlog_node(ctx, user, realm, session_id,
   2314 				   "policy update response",
   2315 				   ret);
   2316 		goto out;
   2317 	}
   2318 
   2319 	if (strcasecmp(req_reason, "User input completed") == 0) {
   2320 		db_add_session_devinfo(ctx, session_id, devinfo);
   2321 		db_add_session_devdetail(ctx, session_id, devdetail);
   2322 		ret = hs20_user_input_complete(ctx, user, realm, dmacc,
   2323 					       session_id);
   2324 		hs20_eventlog_node(ctx, user, realm, session_id,
   2325 				   "user input completed response", ret);
   2326 		goto out;
   2327 	}
   2328 
   2329 	if (strcasecmp(req_reason, "Certificate enrollment completed") == 0) {
   2330 		ret = hs20_cert_enroll_completed(ctx, user, realm, dmacc,
   2331 						 session_id);
   2332 		hs20_eventlog_node(ctx, user, realm, session_id,
   2333 				   "certificate enrollment response", ret);
   2334 		goto out;
   2335 	}
   2336 
   2337 	if (strcasecmp(req_reason, "Certificate enrollment failed") == 0) {
   2338 		ret = hs20_cert_enroll_failed(ctx, user, realm, dmacc,
   2339 					      session_id);
   2340 		hs20_eventlog_node(ctx, user, realm, session_id,
   2341 				   "certificate enrollment failed response",
   2342 				   ret);
   2343 		goto out;
   2344 	}
   2345 
   2346 	if (strcasecmp(req_reason, "Subscription provisioning") == 0) {
   2347 		ret = hs20_sim_provisioning(ctx, user, realm, dmacc,
   2348 					    session_id);
   2349 		hs20_eventlog_node(ctx, user, realm, session_id,
   2350 				   "subscription provisioning response",
   2351 				   ret);
   2352 		goto out;
   2353 	}
   2354 
   2355 	debug_print(ctx, 1, "Unsupported requestReason '%s' user '%s'",
   2356 		    req_reason, user);
   2357 out:
   2358 	xml_node_get_attr_value_free(ctx->xml, req_reason_buf);
   2359 	xml_node_get_attr_value_free(ctx->xml, redirect_uri);
   2360 	if (devinfo)
   2361 		xml_node_free(ctx->xml, devinfo);
   2362 	if (devdetail)
   2363 		xml_node_free(ctx->xml, devdetail);
   2364 	return ret;
   2365 }
   2366 
   2367 
   2368 static xml_node_t * build_spp_exchange_complete(struct hs20_svc *ctx,
   2369 						const char *session_id,
   2370 						const char *status,
   2371 						const char *error_code)
   2372 {
   2373 	xml_namespace_t *ns;
   2374 	xml_node_t *spp_node, *node;
   2375 
   2376 	spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
   2377 					"sppExchangeComplete");
   2378 
   2379 
   2380 	xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
   2381 	xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
   2382 	xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
   2383 
   2384 	if (error_code) {
   2385 		node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
   2386 		xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
   2387 				  error_code);
   2388 	}
   2389 
   2390 	return spp_node;
   2391 }
   2392 
   2393 
   2394 static int add_subscription(struct hs20_svc *ctx, const char *session_id)
   2395 {
   2396 	char *user, *realm, *pw, *pw_mm, *pps, *str;
   2397 	char *osu_user, *osu_password, *eap_method;
   2398 	char *policy = NULL;
   2399 	char *sql;
   2400 	int ret = -1;
   2401 	char *free_account;
   2402 	int free_acc;
   2403 	char *type;
   2404 	int cert = 0;
   2405 	char *cert_pem, *fingerprint;
   2406 	const char *method;
   2407 
   2408 	user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
   2409 	realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
   2410 	pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
   2411 	pw_mm = db_get_session_val(ctx, NULL, NULL, session_id,
   2412 				   "machine_managed");
   2413 	pps = db_get_session_val(ctx, NULL, NULL, session_id, "pps");
   2414 	cert_pem = db_get_session_val(ctx, NULL, NULL, session_id, "cert_pem");
   2415 	fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
   2416 	type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
   2417 	if (type && strcmp(type, "cert") == 0)
   2418 		cert = 1;
   2419 	free(type);
   2420 	osu_user = db_get_session_val(ctx, NULL, NULL, session_id, "osu_user");
   2421 	osu_password = db_get_session_val(ctx, NULL, NULL, session_id,
   2422 					  "osu_password");
   2423 	eap_method = db_get_session_val(ctx, NULL, NULL, session_id,
   2424 					"eap_method");
   2425 
   2426 	if (!user || !realm || !pw) {
   2427 		debug_print(ctx, 1, "Could not find session info from DB for "
   2428 			    "the new subscription");
   2429 		goto out;
   2430 	}
   2431 
   2432 	free_account = db_get_osu_config_val(ctx, realm, "free_account");
   2433 	free_acc = free_account && strcmp(free_account, user) == 0;
   2434 	free(free_account);
   2435 
   2436 	policy = db_get_osu_config_val(ctx, realm, "sim_policy");
   2437 
   2438 	debug_print(ctx, 1,
   2439 		    "New subscription: user='%s' realm='%s' free_acc=%d",
   2440 		    user, realm, free_acc);
   2441 	debug_print(ctx, 1, "New subscription: pps='%s'", pps);
   2442 
   2443 	sql = sqlite3_mprintf("UPDATE eventlog SET user=%Q, realm=%Q WHERE "
   2444 			      "sessionid=%Q AND (user='' OR user IS NULL)",
   2445 			      user, realm, session_id);
   2446 	if (sql) {
   2447 		debug_print(ctx, 1, "DB: %s", sql);
   2448 		if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
   2449 			debug_print(ctx, 1, "Failed to update eventlog in "
   2450 				    "sqlite database: %s",
   2451 				    sqlite3_errmsg(ctx->db));
   2452 		}
   2453 		sqlite3_free(sql);
   2454 	}
   2455 
   2456 	if (free_acc) {
   2457 		hs20_eventlog(ctx, user, realm, session_id,
   2458 			      "completed shared free account registration",
   2459 			      NULL);
   2460 		ret = 0;
   2461 		goto out;
   2462 	}
   2463 
   2464 	str = db_get_session_val(ctx, NULL, NULL, session_id, "mac_addr");
   2465 
   2466 	if (eap_method && eap_method[0])
   2467 		method = eap_method;
   2468 	else
   2469 		method = cert ? "TLS" : "TTLS-MSCHAPV2";
   2470 	sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,methods,cert,cert_pem,machine_managed,mac_addr,osu_user,osu_password,policy) VALUES (%Q,%Q,%d,%Q,%Q,%Q,%d,%Q,%Q,%Q,%Q)",
   2471 			      user, realm, cert ? 0 : 1,
   2472 			      method,
   2473 			      fingerprint ? fingerprint : "",
   2474 			      cert_pem ? cert_pem : "",
   2475 			      pw_mm && atoi(pw_mm) ? 1 : 0,
   2476 			      str ? str : "",
   2477 			      osu_user ? osu_user : "",
   2478 			      osu_password ? osu_password : "",
   2479 			      policy ? policy : "");
   2480 	free(str);
   2481 	if (sql == NULL)
   2482 		goto out;
   2483 	debug_print(ctx, 1, "DB: %s", sql);
   2484 	if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
   2485 		debug_print(ctx, 1, "Failed to add user in sqlite database: %s",
   2486 			    sqlite3_errmsg(ctx->db));
   2487 		sqlite3_free(sql);
   2488 		goto out;
   2489 	}
   2490 	sqlite3_free(sql);
   2491 
   2492 	if (cert)
   2493 		ret = 0;
   2494 	else
   2495 		ret = update_password(ctx, user, realm, pw, 0);
   2496 	if (ret < 0) {
   2497 		sql = sqlite3_mprintf("DELETE FROM users WHERE identity=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
   2498 				      user, realm);
   2499 		if (sql) {
   2500 			debug_print(ctx, 1, "DB: %s", sql);
   2501 			sqlite3_exec(ctx->db, sql, NULL, NULL, NULL);
   2502 			sqlite3_free(sql);
   2503 		}
   2504 	}
   2505 
   2506 	if (pps)
   2507 		db_update_mo_str(ctx, user, realm, "pps", pps);
   2508 
   2509 	str = db_get_session_val(ctx, NULL, NULL, session_id, "devinfo");
   2510 	if (str) {
   2511 		db_update_mo_str(ctx, user, realm, "devinfo", str);
   2512 		free(str);
   2513 	}
   2514 
   2515 	str = db_get_session_val(ctx, NULL, NULL, session_id, "devdetail");
   2516 	if (str) {
   2517 		db_update_mo_str(ctx, user, realm, "devdetail", str);
   2518 		free(str);
   2519 	}
   2520 
   2521 	if (cert && user) {
   2522 		const char *serialnum;
   2523 
   2524 		str = db_get_session_val(ctx, NULL, NULL, session_id,
   2525 					 "mac_addr");
   2526 
   2527 		if (os_strncmp(user, "cert-", 5) == 0)
   2528 			serialnum = user + 5;
   2529 		else
   2530 			serialnum = "";
   2531 		sql = sqlite3_mprintf("INSERT OR REPLACE INTO cert_enroll (mac_addr,user,realm,serialnum) VALUES(%Q,%Q,%Q,%Q)",
   2532 				      str ? str : "", user, realm ? realm : "",
   2533 				      serialnum);
   2534 		free(str);
   2535 		if (sql) {
   2536 			debug_print(ctx, 1, "DB: %s", sql);
   2537 			if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) !=
   2538 			    SQLITE_OK) {
   2539 				debug_print(ctx, 1,
   2540 					    "Failed to add cert_enroll entry into sqlite database: %s",
   2541 					    sqlite3_errmsg(ctx->db));
   2542 			}
   2543 			sqlite3_free(sql);
   2544 		}
   2545 	}
   2546 
   2547 	str = db_get_session_val(ctx, NULL, NULL, session_id,
   2548 				 "mobile_identifier_hash");
   2549 	if (str) {
   2550 		sql = sqlite3_mprintf("DELETE FROM sim_provisioning WHERE mobile_identifier_hash=%Q",
   2551 				      str);
   2552 		if (sql) {
   2553 			debug_print(ctx, 1, "DB: %s", sql);
   2554 			if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) !=
   2555 			    SQLITE_OK) {
   2556 				debug_print(ctx, 1,
   2557 					    "Failed to delete pending sim_provisioning entry: %s",
   2558 					    sqlite3_errmsg(ctx->db));
   2559 			}
   2560 			sqlite3_free(sql);
   2561 		}
   2562 		os_free(str);
   2563 	}
   2564 
   2565 	if (ret == 0) {
   2566 		hs20_eventlog(ctx, user, realm, session_id,
   2567 			      "completed subscription registration", NULL);
   2568 	}
   2569 
   2570 out:
   2571 	free(user);
   2572 	free(realm);
   2573 	free(pw);
   2574 	free(pw_mm);
   2575 	free(pps);
   2576 	free(cert_pem);
   2577 	free(fingerprint);
   2578 	free(osu_user);
   2579 	free(osu_password);
   2580 	free(eap_method);
   2581 	os_free(policy);
   2582 	return ret;
   2583 }
   2584 
   2585 
   2586 static xml_node_t * hs20_spp_update_response(struct hs20_svc *ctx,
   2587 					     xml_node_t *node,
   2588 					     const char *user,
   2589 					     const char *realm,
   2590 					     const char *session_id,
   2591 					     int dmacc)
   2592 {
   2593 	char *status;
   2594 	xml_node_t *ret;
   2595 	char *val;
   2596 	enum hs20_session_operation oper;
   2597 
   2598 	status = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
   2599 					    "sppStatus");
   2600 	if (status == NULL) {
   2601 		debug_print(ctx, 1, "No sppStatus attribute");
   2602 		return NULL;
   2603 	}
   2604 
   2605 	debug_print(ctx, 1, "sppUpdateResponse: sppStatus: %s  sessionID: %s",
   2606 		    status, session_id);
   2607 
   2608 	val = db_get_session_val(ctx, NULL, NULL, session_id, "operation");
   2609 	if (!val) {
   2610 		debug_print(ctx, 1,
   2611 			    "No session active for sessionID: %s",
   2612 			    session_id);
   2613 		oper = NO_OPERATION;
   2614 	} else
   2615 		oper = atoi(val);
   2616 
   2617 	if (strcasecmp(status, "OK") == 0) {
   2618 		char *new_pw = NULL;
   2619 
   2620 		xml_node_get_attr_value_free(ctx->xml, status);
   2621 
   2622 		if (oper == USER_REMEDIATION) {
   2623 			new_pw = db_get_session_val(ctx, user, realm,
   2624 						    session_id, "password");
   2625 			if (new_pw == NULL || strlen(new_pw) == 0) {
   2626 				free(new_pw);
   2627 				ret = build_spp_exchange_complete(
   2628 					ctx, session_id, "Error occurred",
   2629 					"Other");
   2630 				hs20_eventlog_node(ctx, user, realm,
   2631 						   session_id, "No password "
   2632 						   "had been assigned for "
   2633 						   "session", ret);
   2634 				db_remove_session(ctx, user, realm, session_id);
   2635 				return ret;
   2636 			}
   2637 			oper = UPDATE_PASSWORD;
   2638 		}
   2639 		if (oper == UPDATE_PASSWORD) {
   2640 			if (!new_pw) {
   2641 				new_pw = db_get_session_val(ctx, user, realm,
   2642 							    session_id,
   2643 							    "password");
   2644 				if (!new_pw) {
   2645 					db_remove_session(ctx, user, realm,
   2646 							  session_id);
   2647 					return NULL;
   2648 				}
   2649 			}
   2650 			debug_print(ctx, 1, "Update user '%s' password in DB",
   2651 				    user);
   2652 			if (update_password(ctx, user, realm, new_pw, dmacc) <
   2653 			    0) {
   2654 				debug_print(ctx, 1, "Failed to update user "
   2655 					    "'%s' password in DB", user);
   2656 				ret = build_spp_exchange_complete(
   2657 					ctx, session_id, "Error occurred",
   2658 					"Other");
   2659 				hs20_eventlog_node(ctx, user, realm,
   2660 						   session_id, "Failed to "
   2661 						   "update database", ret);
   2662 				db_remove_session(ctx, user, realm, session_id);
   2663 				return ret;
   2664 			}
   2665 			hs20_eventlog(ctx, user, realm,
   2666 				      session_id, "Updated user password "
   2667 				      "in database", NULL);
   2668 		}
   2669 		if (oper == CLEAR_REMEDIATION) {
   2670 			debug_print(ctx, 1,
   2671 				    "Clear remediation requirement for user '%s' in DB",
   2672 				    user);
   2673 			if (clear_remediation(ctx, user, realm, dmacc) < 0) {
   2674 				debug_print(ctx, 1,
   2675 					    "Failed to clear remediation requirement for user '%s' in DB",
   2676 					    user);
   2677 				ret = build_spp_exchange_complete(
   2678 					ctx, session_id, "Error occurred",
   2679 					"Other");
   2680 				hs20_eventlog_node(ctx, user, realm,
   2681 						   session_id,
   2682 						   "Failed to update database",
   2683 						   ret);
   2684 				db_remove_session(ctx, user, realm, session_id);
   2685 				return ret;
   2686 			}
   2687 			hs20_eventlog(ctx, user, realm,
   2688 				      session_id,
   2689 				      "Cleared remediation requirement in database",
   2690 				      NULL);
   2691 		}
   2692 		if (oper == SUBSCRIPTION_REGISTRATION) {
   2693 			if (add_subscription(ctx, session_id) < 0) {
   2694 				debug_print(ctx, 1, "Failed to add "
   2695 					    "subscription into DB");
   2696 				ret = build_spp_exchange_complete(
   2697 					ctx, session_id, "Error occurred",
   2698 					"Other");
   2699 				hs20_eventlog_node(ctx, user, realm,
   2700 						   session_id, "Failed to "
   2701 						   "update database", ret);
   2702 				db_remove_session(ctx, user, realm, session_id);
   2703 				return ret;
   2704 			}
   2705 		}
   2706 		if (oper == POLICY_REMEDIATION || oper == POLICY_UPDATE) {
   2707 			char *val;
   2708 			val = db_get_val(ctx, user, realm, "remediation",
   2709 					 dmacc);
   2710 			if (val && strcmp(val, "policy") == 0)
   2711 				db_update_val(ctx, user, realm, "remediation",
   2712 					      "", dmacc);
   2713 			free(val);
   2714 		}
   2715 		if (oper == POLICY_UPDATE)
   2716 			db_update_val(ctx, user, realm, "polupd_done", "1",
   2717 				      dmacc);
   2718 		if (oper == CERT_REENROLL) {
   2719 			char *new_user;
   2720 			char event[200];
   2721 
   2722 			new_user = db_get_session_val(ctx, NULL, NULL,
   2723 						      session_id, "user");
   2724 			if (!new_user) {
   2725 				debug_print(ctx, 1,
   2726 					    "Failed to find new user name (cert-serialnum)");
   2727 				ret = build_spp_exchange_complete(
   2728 					ctx, session_id, "Error occurred",
   2729 					"Other");
   2730 				hs20_eventlog_node(ctx, user, realm,
   2731 						   session_id,
   2732 						   "Failed to find new user name (cert reenroll)",
   2733 						   ret);
   2734 				db_remove_session(ctx, NULL, NULL, session_id);
   2735 				return ret;
   2736 			}
   2737 
   2738 			debug_print(ctx, 1,
   2739 				    "Update certificate user entry to use the new serial number (old=%s new=%s)",
   2740 				    user, new_user);
   2741 			os_snprintf(event, sizeof(event), "renamed user to: %s",
   2742 				    new_user);
   2743 			hs20_eventlog(ctx, user, realm, session_id, event,
   2744 				      NULL);
   2745 
   2746 			if (db_update_val(ctx, user, realm, "identity",
   2747 					  new_user, 0) < 0 ||
   2748 			    db_update_val(ctx, new_user, realm, "remediation",
   2749 					  "", 0) < 0) {
   2750 				debug_print(ctx, 1,
   2751 					    "Failed to update user name (cert-serialnum)");
   2752 				ret = build_spp_exchange_complete(
   2753 					ctx, session_id, "Error occurred",
   2754 					"Other");
   2755 				hs20_eventlog_node(ctx, user, realm,
   2756 						   session_id,
   2757 						   "Failed to update user name (cert reenroll)",
   2758 						   ret);
   2759 				db_remove_session(ctx, NULL, NULL, session_id);
   2760 				os_free(new_user);
   2761 				return ret;
   2762 			}
   2763 
   2764 			os_free(new_user);
   2765 		}
   2766 		ret = build_spp_exchange_complete(
   2767 			ctx, session_id,
   2768 			"Exchange complete, release TLS connection", NULL);
   2769 		hs20_eventlog_node(ctx, user, realm, session_id,
   2770 				   "Exchange completed", ret);
   2771 		db_remove_session(ctx, NULL, NULL, session_id);
   2772 		return ret;
   2773 	}
   2774 
   2775 	ret = build_spp_exchange_complete(ctx, session_id, "Error occurred",
   2776 					  "Other");
   2777 	hs20_eventlog_node(ctx, user, realm, session_id, "Error occurred", ret);
   2778 	db_remove_session(ctx, user, realm, session_id);
   2779 	xml_node_get_attr_value_free(ctx->xml, status);
   2780 	return ret;
   2781 }
   2782 
   2783 
   2784 #define SPP_SESSION_ID_LEN 16
   2785 
   2786 static char * gen_spp_session_id(void)
   2787 {
   2788 	FILE *f;
   2789 	int i;
   2790 	char *session;
   2791 
   2792 	session = os_malloc(SPP_SESSION_ID_LEN * 2 + 1);
   2793 	if (session == NULL)
   2794 		return NULL;
   2795 
   2796 	f = fopen("/dev/urandom", "r");
   2797 	if (f == NULL) {
   2798 		os_free(session);
   2799 		return NULL;
   2800 	}
   2801 	for (i = 0; i < SPP_SESSION_ID_LEN; i++)
   2802 		os_snprintf(session + i * 2, 3, "%02x", fgetc(f));
   2803 
   2804 	fclose(f);
   2805 	return session;
   2806 }
   2807 
   2808 xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node,
   2809 				     const char *auth_user,
   2810 				     const char *auth_realm, int dmacc)
   2811 {
   2812 	xml_node_t *ret = NULL;
   2813 	char *session_id;
   2814 	const char *op_name;
   2815 	char *xml_err;
   2816 	char fname[200];
   2817 
   2818 	debug_dump_node(ctx, "received request", node);
   2819 
   2820 	if (!dmacc && auth_user && auth_realm) {
   2821 		char *real;
   2822 		real = db_get_val(ctx, auth_user, auth_realm, "identity", 0);
   2823 		if (!real) {
   2824 			real = db_get_val(ctx, auth_user, auth_realm,
   2825 					  "identity", 1);
   2826 			if (real)
   2827 				dmacc = 1;
   2828 		}
   2829 		os_free(real);
   2830 	}
   2831 
   2832 	snprintf(fname, sizeof(fname), "%s/spp/spp.xsd", ctx->root_dir);
   2833 	if (xml_validate(ctx->xml, node, fname, &xml_err) < 0) {
   2834 		/*
   2835 		 * We may not be able to extract the sessionID from invalid
   2836 		 * input, but well, we can try.
   2837 		 */
   2838 		session_id = xml_node_get_attr_value_ns(ctx->xml, node,
   2839 							SPP_NS_URI,
   2840 							"sessionID");
   2841 		debug_print(ctx, 1,
   2842 			    "SPP message failed validation, xsd file: %s  xml-error: %s",
   2843 			    fname, xml_err);
   2844 		hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
   2845 				   "SPP message failed validation", node);
   2846 		hs20_eventlog(ctx, auth_user, auth_realm, session_id,
   2847 			      "Validation errors", xml_err);
   2848 		os_free(xml_err);
   2849 		xml_node_get_attr_value_free(ctx->xml, session_id);
   2850 		/* TODO: what to return here? */
   2851 		ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
   2852 					   "SppValidationError");
   2853 		return ret;
   2854 	}
   2855 
   2856 	session_id = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
   2857 						"sessionID");
   2858 	if (session_id) {
   2859 		char *tmp;
   2860 		debug_print(ctx, 1, "Received sessionID %s", session_id);
   2861 		tmp = os_strdup(session_id);
   2862 		xml_node_get_attr_value_free(ctx->xml, session_id);
   2863 		if (tmp == NULL)
   2864 			return NULL;
   2865 		session_id = tmp;
   2866 	} else {
   2867 		session_id = gen_spp_session_id();
   2868 		if (session_id == NULL) {
   2869 			debug_print(ctx, 1, "Failed to generate sessionID");
   2870 			return NULL;
   2871 		}
   2872 		debug_print(ctx, 1, "Generated sessionID %s", session_id);
   2873 	}
   2874 
   2875 	op_name = xml_node_get_localname(ctx->xml, node);
   2876 	if (op_name == NULL) {
   2877 		debug_print(ctx, 1, "Could not get op_name");
   2878 		return NULL;
   2879 	}
   2880 
   2881 	if (strcmp(op_name, "sppPostDevData") == 0) {
   2882 		hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
   2883 				   "sppPostDevData received and validated",
   2884 				   node);
   2885 		ret = hs20_spp_post_dev_data(ctx, node, auth_user, auth_realm,
   2886 					     session_id, dmacc);
   2887 	} else if (strcmp(op_name, "sppUpdateResponse") == 0) {
   2888 		hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
   2889 				   "sppUpdateResponse received and validated",
   2890 				   node);
   2891 		ret = hs20_spp_update_response(ctx, node, auth_user,
   2892 					       auth_realm, session_id, dmacc);
   2893 	} else {
   2894 		hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
   2895 				   "Unsupported SPP message received and "
   2896 				   "validated", node);
   2897 		debug_print(ctx, 1, "Unsupported operation '%s'", op_name);
   2898 		/* TODO: what to return here? */
   2899 		ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
   2900 					   "SppUnknownCommandError");
   2901 	}
   2902 	os_free(session_id);
   2903 
   2904 	if (ret == NULL) {
   2905 		/* TODO: what to return here? */
   2906 		ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
   2907 					   "SppInternalError");
   2908 	}
   2909 
   2910 	return ret;
   2911 }
   2912 
   2913 
   2914 int hs20_spp_server_init(struct hs20_svc *ctx)
   2915 {
   2916 	char fname[200];
   2917 	ctx->db = NULL;
   2918 	snprintf(fname, sizeof(fname), "%s/AS/DB/eap_user.db", ctx->root_dir);
   2919 	if (sqlite3_open(fname, &ctx->db)) {
   2920 		printf("Failed to open sqlite database: %s\n",
   2921 		       sqlite3_errmsg(ctx->db));
   2922 		sqlite3_close(ctx->db);
   2923 		return -1;
   2924 	}
   2925 
   2926 	return 0;
   2927 }
   2928 
   2929 
   2930 void hs20_spp_server_deinit(struct hs20_svc *ctx)
   2931 {
   2932 	sqlite3_close(ctx->db);
   2933 	ctx->db = NULL;
   2934 }
   2935