xref: /aosp_15_r20/external/wpa_supplicant_8/hs20/server/spp_server.c (revision 03f9172ca588f91df233974f4258bab95191f931)
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 
db_add_session(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid,const char * pw,const char * redirect_uri,enum hs20_session_operation operation,const u8 * mac_addr)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 
db_update_session_password(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid,const char * pw)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 
db_update_session_machine_managed(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid,const int pw_mm)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 
db_add_session_pps(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid,xml_node_t * node)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 
db_add_session_devinfo(struct hs20_svc * ctx,const char * sessionid,xml_node_t * node)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 
db_add_session_devdetail(struct hs20_svc * ctx,const char * sessionid,xml_node_t * node)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 
db_add_session_dmacc(struct hs20_svc * ctx,const char * sessionid,const char * username,const char * password)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 
db_add_session_eap_method(struct hs20_svc * ctx,const char * sessionid,const char * method)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 
db_add_session_id_hash(struct hs20_svc * ctx,const char * sessionid,const char * id_hash)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 
db_remove_session(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid)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 
hs20_eventlog(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid,const char * notes,const char * dump)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 
hs20_eventlog_node(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid,const char * notes,xml_node_t * node)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 
db_update_mo_str(struct hs20_svc * ctx,const char * user,const char * realm,const char * name,const char * str)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 
db_update_mo(struct hs20_svc * ctx,const char * user,const char * realm,const char * name,xml_node_t * mo)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 
add_text_node(struct hs20_svc * ctx,xml_node_t * parent,const char * name,const char * value)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 
add_text_node_conf(struct hs20_svc * ctx,const char * realm,xml_node_t * parent,const char * name,const char * field)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 
add_text_node_conf_corrupt(struct hs20_svc * ctx,const char * realm,xml_node_t * parent,const char * name,const char * field)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 
new_password(char * buf,int buflen)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 
get_db_field(void * ctx,int argc,char * argv[],char * col[])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 
db_get_val(struct hs20_svc * ctx,const char * user,const char * realm,const char * field,int dmacc)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 
db_update_val(struct hs20_svc * ctx,const char * user,const char * realm,const char * field,const char * val,int dmacc)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 
db_get_session_val(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,const char * field)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 
update_password(struct hs20_svc * ctx,const char * user,const char * realm,const char * pw,int dmacc)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 
clear_remediation(struct hs20_svc * ctx,const char * user,const char * realm,int dmacc)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 
add_eap_ttls(struct hs20_svc * ctx,xml_node_t * parent)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 
build_username_password(struct hs20_svc * ctx,xml_node_t * parent,const char * user,const char * pw)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 = base64_encode(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 
add_username_password(struct hs20_svc * ctx,xml_node_t * cred,const char * user,const char * pw,int machine_managed)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 
add_creation_date(struct hs20_svc * ctx,xml_node_t * cred)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 
build_credential_pw(struct hs20_svc * ctx,const char * user,const char * realm,const char * pw,int machine_managed)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 
build_credential(struct hs20_svc * ctx,const char * user,const char * realm,char * new_pw,size_t new_pw_len)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 
build_credential_cert(struct hs20_svc * ctx,const char * user,const char * realm,const char * cert_fingerprint)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 
build_post_dev_data_response(struct hs20_svc * ctx,xml_namespace_t ** ret_ns,const char * session_id,const char * status,const char * error_code)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 
add_update_node(struct hs20_svc * ctx,xml_node_t * spp_node,xml_namespace_t * ns,const char * uri,xml_node_t * upd_node)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 
read_subrem_file(struct hs20_svc * ctx,const char * subrem_id,char * uri,size_t uri_size)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 
build_sub_rem_resp(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,int machine_rem,int dmacc)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 
machine_remediation(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,int dmacc)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 
cert_reenroll(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id)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 
policy_remediation(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,int dmacc)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 
browser_remediation(struct hs20_svc * ctx,const char * session_id,const char * redirect_uri,const char * uri)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 
user_remediation(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,const char * redirect_uri)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 
free_remediation(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,const char * redirect_uri)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 
no_sub_rem(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id)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 
hs20_subscription_remediation(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,int dmacc,const char * redirect_uri)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 
read_policy_file(struct hs20_svc * ctx,const char * policy_id)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 
update_policy_update_uri(struct hs20_svc * ctx,const char * realm,xml_node_t * policy)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 
build_policy(struct hs20_svc * ctx,const char * user,const char * realm,int use_dmacc)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 
hs20_policy_update(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,int dmacc)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 
spp_get_mo(struct hs20_svc * ctx,xml_node_t * node,const char * urn,int * valid,char ** ret_err)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 
spp_exec_upload_mo(struct hs20_svc * ctx,const char * session_id,const char * urn)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 
hs20_subscription_registration(struct hs20_svc * ctx,const char * realm,const char * session_id,const char * redirect_uri,const u8 * mac_addr)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) {
1389 		hs20_eventlog(ctx, NULL, realm, session_id,
1390 			      "signup_url not configured in osu_config", NULL);
1391 		return NULL;
1392 	}
1393 
1394 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
1395 						NULL);
1396 	if (spp_node == NULL)
1397 		return NULL;
1398 
1399 	exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
1400 
1401 	snprintf(uri, sizeof(uri), "%s%s", val, session_id);
1402 	os_free(val);
1403 	xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI",
1404 			     uri);
1405 	return spp_node;
1406 }
1407 
1408 
hs20_user_input_remediation(struct hs20_svc * ctx,const char * user,const char * realm,int dmacc,const char * session_id)1409 static xml_node_t * hs20_user_input_remediation(struct hs20_svc *ctx,
1410 						const char *user,
1411 						const char *realm, int dmacc,
1412 						const char *session_id)
1413 {
1414 	return build_sub_rem_resp(ctx, user, realm, session_id, 0, dmacc);
1415 }
1416 
1417 
db_get_osu_config_val(struct hs20_svc * ctx,const char * realm,const char * field)1418 static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm,
1419 				    const char *field)
1420 {
1421 	char *cmd;
1422 	struct get_db_field_data data;
1423 
1424 	cmd = sqlite3_mprintf("SELECT value FROM osu_config WHERE realm=%Q AND "
1425 			      "field=%Q", realm, field);
1426 	if (cmd == NULL)
1427 		return NULL;
1428 	debug_print(ctx, 1, "DB: %s", cmd);
1429 	memset(&data, 0, sizeof(data));
1430 	data.field = "value";
1431 	if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
1432 	{
1433 		debug_print(ctx, 1, "DB: Could not find osu_config %s: %s",
1434 			    realm, sqlite3_errmsg(ctx->db));
1435 		sqlite3_free(cmd);
1436 		return NULL;
1437 	}
1438 	sqlite3_free(cmd);
1439 
1440 	debug_print(ctx, 1, "DB: return '%s'", data.value);
1441 	return data.value;
1442 }
1443 
1444 
build_pps(struct hs20_svc * ctx,const char * user,const char * realm,const char * pw,const char * cert,int machine_managed,const char * test,const char * imsi,const char * dmacc_username,const char * dmacc_password,xml_node_t * policy_node)1445 static xml_node_t * build_pps(struct hs20_svc *ctx,
1446 			      const char *user, const char *realm,
1447 			      const char *pw, const char *cert,
1448 			      int machine_managed, const char *test,
1449 			      const char *imsi, const char *dmacc_username,
1450 			      const char *dmacc_password,
1451 			      xml_node_t *policy_node)
1452 {
1453 	xml_node_t *pps, *c, *trust, *aaa, *aaa1, *upd, *homesp, *p;
1454 	xml_node_t *cred, *eap, *userpw;
1455 
1456 	pps = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
1457 				   "PerProviderSubscription");
1458 	if (!pps) {
1459 		xml_node_free(ctx->xml, policy_node);
1460 		return NULL;
1461 	}
1462 
1463 	add_text_node(ctx, pps, "UpdateIdentifier", "1");
1464 
1465 	c = xml_node_create(ctx->xml, pps, NULL, "Cred01");
1466 
1467 	add_text_node(ctx, c, "CredentialPriority", "1");
1468 
1469 	if (imsi)
1470 		goto skip_aaa_trust_root;
1471 	aaa = xml_node_create(ctx->xml, c, NULL, "AAAServerTrustRoot");
1472 	aaa1 = xml_node_create(ctx->xml, aaa, NULL, "AAA1");
1473 	add_text_node_conf(ctx, realm, aaa1, "CertURL",
1474 			   "aaa_trust_root_cert_url");
1475 	if (test && os_strcmp(test, "corrupt_aaa_hash") == 0) {
1476 		debug_print(ctx, 1,
1477 			    "TEST: Corrupt PPS/Cred*/AAAServerTrustRoot/Root*/CertSHA256FingerPrint");
1478 		add_text_node_conf_corrupt(ctx, realm, aaa1,
1479 					   "CertSHA256Fingerprint",
1480 					   "aaa_trust_root_cert_fingerprint");
1481 	} else {
1482 		add_text_node_conf(ctx, realm, aaa1, "CertSHA256Fingerprint",
1483 				   "aaa_trust_root_cert_fingerprint");
1484 	}
1485 
1486 	if (test && os_strcmp(test, "corrupt_polupd_hash") == 0) {
1487 		debug_print(ctx, 1,
1488 			    "TEST: Corrupt PPS/Cred*/Policy/PolicyUpdate/Trustroot/CertSHA256FingerPrint");
1489 		p = xml_node_create(ctx->xml, c, NULL, "Policy");
1490 		upd = xml_node_create(ctx->xml, p, NULL, "PolicyUpdate");
1491 		add_text_node(ctx, upd, "UpdateInterval", "30");
1492 		add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated");
1493 		add_text_node(ctx, upd, "Restriction", "Unrestricted");
1494 		add_text_node_conf(ctx, realm, upd, "URI", "policy_url");
1495 		trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
1496 		add_text_node_conf(ctx, realm, trust, "CertURL",
1497 				   "policy_trust_root_cert_url");
1498 		add_text_node_conf_corrupt(ctx, realm, trust,
1499 					   "CertSHA256Fingerprint",
1500 					   "policy_trust_root_cert_fingerprint");
1501 	}
1502 skip_aaa_trust_root:
1503 
1504 	upd = xml_node_create(ctx->xml, c, NULL, "SubscriptionUpdate");
1505 	add_text_node(ctx, upd, "UpdateInterval", "4294967295");
1506 	add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated");
1507 	add_text_node(ctx, upd, "Restriction", "HomeSP");
1508 	add_text_node_conf(ctx, realm, upd, "URI", "spp_http_auth_url");
1509 	trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
1510 	add_text_node_conf(ctx, realm, trust, "CertURL", "trust_root_cert_url");
1511 	if (test && os_strcmp(test, "corrupt_subrem_hash") == 0) {
1512 		debug_print(ctx, 1,
1513 			    "TEST: Corrupt PPS/Cred*/SubscriptionUpdate/Trustroot/CertSHA256FingerPrint");
1514 		add_text_node_conf_corrupt(ctx, realm, trust,
1515 					   "CertSHA256Fingerprint",
1516 					   "trust_root_cert_fingerprint");
1517 	} else {
1518 		add_text_node_conf(ctx, realm, trust, "CertSHA256Fingerprint",
1519 				   "trust_root_cert_fingerprint");
1520 	}
1521 
1522 	if (dmacc_username &&
1523 	    !build_username_password(ctx, upd, dmacc_username,
1524 				     dmacc_password)) {
1525 		xml_node_free(ctx->xml, pps);
1526 		xml_node_free(ctx->xml, policy_node);
1527 		return NULL;
1528 	}
1529 
1530 	if (policy_node)
1531 		xml_node_add_child(ctx->xml, c, policy_node);
1532 
1533 	homesp = xml_node_create(ctx->xml, c, NULL, "HomeSP");
1534 	add_text_node_conf(ctx, realm, homesp, "FriendlyName", "friendly_name");
1535 	add_text_node_conf(ctx, realm, homesp, "FQDN", "fqdn");
1536 
1537 	xml_node_create(ctx->xml, c, NULL, "SubscriptionParameters");
1538 
1539 	cred = xml_node_create(ctx->xml, c, NULL, "Credential");
1540 	add_creation_date(ctx, cred);
1541 	if (imsi) {
1542 		xml_node_t *sim;
1543 		const char *type = "18"; /* default to EAP-SIM */
1544 
1545 		sim = xml_node_create(ctx->xml, cred, NULL, "SIM");
1546 		add_text_node(ctx, sim, "IMSI", imsi);
1547 		if (ctx->eap_method && os_strcmp(ctx->eap_method, "AKA") == 0)
1548 			type = "23";
1549 		else if (ctx->eap_method &&
1550 			 os_strcmp(ctx->eap_method, "AKA'") == 0)
1551 			type = "50";
1552 		add_text_node(ctx, sim, "EAPType", type);
1553 	} else if (cert) {
1554 		xml_node_t *dc;
1555 		dc = xml_node_create(ctx->xml, cred, NULL,
1556 				     "DigitalCertificate");
1557 		add_text_node(ctx, dc, "CertificateType", "x509v3");
1558 		add_text_node(ctx, dc, "CertSHA256Fingerprint", cert);
1559 	} else {
1560 		userpw = build_username_password(ctx, cred, user, pw);
1561 		add_text_node(ctx, userpw, "MachineManaged",
1562 			      machine_managed ? "TRUE" : "FALSE");
1563 		eap = xml_node_create(ctx->xml, userpw, NULL, "EAPMethod");
1564 		add_text_node(ctx, eap, "EAPType", "21");
1565 		add_text_node(ctx, eap, "InnerMethod", "MS-CHAP-V2");
1566 	}
1567 	add_text_node(ctx, cred, "Realm", realm);
1568 
1569 	return pps;
1570 }
1571 
1572 
spp_exec_get_certificate(struct hs20_svc * ctx,const char * session_id,const char * user,const char * realm,int add_est_user)1573 static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx,
1574 					     const char *session_id,
1575 					     const char *user,
1576 					     const char *realm,
1577 					     int add_est_user)
1578 {
1579 	xml_namespace_t *ns;
1580 	xml_node_t *spp_node, *enroll, *exec_node;
1581 	char *val;
1582 	char password[11];
1583 	char *b64;
1584 
1585 	if (add_est_user && new_password(password, sizeof(password)) < 0)
1586 		return NULL;
1587 
1588 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
1589 						NULL);
1590 	if (spp_node == NULL)
1591 		return NULL;
1592 
1593 	exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
1594 
1595 	enroll = xml_node_create(ctx->xml, exec_node, ns, "getCertificate");
1596 	xml_node_add_attr(ctx->xml, enroll, NULL, "enrollmentProtocol", "EST");
1597 
1598 	val = db_get_osu_config_val(ctx, realm, "est_url");
1599 	xml_node_create_text(ctx->xml, enroll, ns, "enrollmentServerURI",
1600 			     val ? val : "");
1601 	os_free(val);
1602 
1603 	if (!add_est_user)
1604 		return spp_node;
1605 
1606 	xml_node_create_text(ctx->xml, enroll, ns, "estUserID", user);
1607 
1608 	b64 = base64_encode(password, strlen(password), NULL);
1609 	if (b64 == NULL) {
1610 		xml_node_free(ctx->xml, spp_node);
1611 		return NULL;
1612 	}
1613 	xml_node_create_text(ctx->xml, enroll, ns, "estPassword", b64);
1614 	free(b64);
1615 
1616 	db_update_session_password(ctx, user, realm, session_id, password);
1617 
1618 	return spp_node;
1619 }
1620 
1621 
hs20_user_input_registration(struct hs20_svc * ctx,const char * session_id,int enrollment_done)1622 static xml_node_t * hs20_user_input_registration(struct hs20_svc *ctx,
1623 						 const char *session_id,
1624 						 int enrollment_done)
1625 {
1626 	xml_namespace_t *ns;
1627 	xml_node_t *spp_node, *node = NULL;
1628 	xml_node_t *pps, *tnds;
1629 	char buf[400];
1630 	char *str;
1631 	char *user, *realm, *pw, *type, *mm, *test;
1632 	const char *status;
1633 	int cert = 0;
1634 	int machine_managed = 0;
1635 	char *fingerprint;
1636 
1637 	user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
1638 	realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
1639 	pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
1640 
1641 	if (!user || !realm || !pw) {
1642 		debug_print(ctx, 1, "Could not find session info from DB for "
1643 			    "the new subscription");
1644 		free(user);
1645 		free(realm);
1646 		free(pw);
1647 		return NULL;
1648 	}
1649 
1650 	mm = db_get_session_val(ctx, NULL, NULL, session_id, "machine_managed");
1651 	if (mm && atoi(mm))
1652 		machine_managed = 1;
1653 	free(mm);
1654 
1655 	type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
1656 	if (type && strcmp(type, "cert") == 0)
1657 		cert = 1;
1658 	free(type);
1659 
1660 	if (cert && !enrollment_done) {
1661 		xml_node_t *ret;
1662 		hs20_eventlog(ctx, user, realm, session_id,
1663 			      "request client certificate enrollment", NULL);
1664 		ret = spp_exec_get_certificate(ctx, session_id, user, realm, 1);
1665 		free(user);
1666 		free(realm);
1667 		free(pw);
1668 		return ret;
1669 	}
1670 
1671 	if (!cert && strlen(pw) == 0) {
1672 		machine_managed = 1;
1673 		free(pw);
1674 		pw = malloc(11);
1675 		if (pw == NULL || new_password(pw, 11) < 0) {
1676 			free(user);
1677 			free(realm);
1678 			free(pw);
1679 			return NULL;
1680 		}
1681 	}
1682 
1683 	status = "Provisioning complete, request sppUpdateResponse";
1684 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1685 						NULL);
1686 	if (spp_node == NULL)
1687 		return NULL;
1688 
1689 	fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
1690 	test = db_get_session_val(ctx, NULL, NULL, session_id, "test");
1691 	if (test)
1692 		debug_print(ctx, 1, "TEST: Requested special behavior: %s",
1693 			    test);
1694 	pps = build_pps(ctx, user, realm, pw,
1695 			fingerprint ? fingerprint : NULL, machine_managed,
1696 			test, NULL, NULL, NULL, NULL);
1697 	free(fingerprint);
1698 	free(test);
1699 	if (!pps) {
1700 		xml_node_free(ctx->xml, spp_node);
1701 		free(user);
1702 		free(realm);
1703 		free(pw);
1704 		return NULL;
1705 	}
1706 
1707 	debug_print(ctx, 1, "Request DB subscription registration on success "
1708 		    "notification");
1709 	if (machine_managed) {
1710 		db_update_session_password(ctx, user, realm, session_id, pw);
1711 		db_update_session_machine_managed(ctx, user, realm, session_id,
1712 						  machine_managed);
1713 	}
1714 	db_add_session_pps(ctx, user, realm, session_id, pps);
1715 
1716 	hs20_eventlog_node(ctx, user, realm, session_id,
1717 			   "new subscription", pps);
1718 	free(user);
1719 	free(pw);
1720 
1721 	tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL);
1722 	xml_node_free(ctx->xml, pps);
1723 	if (!tnds) {
1724 		xml_node_free(ctx->xml, spp_node);
1725 		free(realm);
1726 		return NULL;
1727 	}
1728 
1729 	str = xml_node_to_str(ctx->xml, tnds);
1730 	xml_node_free(ctx->xml, tnds);
1731 	if (str == NULL) {
1732 		xml_node_free(ctx->xml, spp_node);
1733 		free(realm);
1734 		return NULL;
1735 	}
1736 
1737 	node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str);
1738 	free(str);
1739 	snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm);
1740 	free(realm);
1741 	xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf);
1742 	xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS);
1743 
1744 	return spp_node;
1745 }
1746 
1747 
hs20_user_input_free_remediation(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id)1748 static xml_node_t * hs20_user_input_free_remediation(struct hs20_svc *ctx,
1749 						     const char *user,
1750 						     const char *realm,
1751 						     const char *session_id)
1752 {
1753 	xml_namespace_t *ns;
1754 	xml_node_t *spp_node;
1755 	xml_node_t *cred;
1756 	char buf[400];
1757 	char *status;
1758 	char *free_account, *pw;
1759 
1760 	free_account = db_get_osu_config_val(ctx, realm, "free_account");
1761 	if (free_account == NULL)
1762 		return NULL;
1763 	pw = db_get_val(ctx, free_account, realm, "password", 0);
1764 	if (pw == NULL) {
1765 		free(free_account);
1766 		return NULL;
1767 	}
1768 
1769 	cred = build_credential_pw(ctx, free_account, realm, pw, 1);
1770 	free(free_account);
1771 	free(pw);
1772 	if (!cred) {
1773 		xml_node_free(ctx->xml, cred);
1774 		return NULL;
1775 	}
1776 
1777 	status = "Remediation complete, request sppUpdateResponse";
1778 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1779 						NULL);
1780 	if (spp_node == NULL)
1781 		return NULL;
1782 
1783 	snprintf(buf, sizeof(buf),
1784 		 "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
1785 		 realm);
1786 
1787 	if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
1788 		xml_node_free(ctx->xml, spp_node);
1789 		return NULL;
1790 	}
1791 
1792 	hs20_eventlog_node(ctx, user, realm, session_id,
1793 			   "free/public remediation", cred);
1794 	xml_node_free(ctx->xml, cred);
1795 
1796 	return spp_node;
1797 }
1798 
1799 
hs20_user_input_complete(struct hs20_svc * ctx,const char * user,const char * realm,int dmacc,const char * session_id)1800 static xml_node_t * hs20_user_input_complete(struct hs20_svc *ctx,
1801 					     const char *user,
1802 					     const char *realm, int dmacc,
1803 					     const char *session_id)
1804 {
1805 	char *val;
1806 	enum hs20_session_operation oper;
1807 
1808 	val = db_get_session_val(ctx, user, realm, session_id, "operation");
1809 	if (val == NULL) {
1810 		debug_print(ctx, 1, "No session %s found to continue",
1811 			    session_id);
1812 		return NULL;
1813 	}
1814 	oper = atoi(val);
1815 	free(val);
1816 
1817 	if (oper == USER_REMEDIATION) {
1818 		return hs20_user_input_remediation(ctx, user, realm, dmacc,
1819 						   session_id);
1820 	}
1821 
1822 	if (oper == FREE_REMEDIATION) {
1823 		return hs20_user_input_free_remediation(ctx, user, realm,
1824 							session_id);
1825 	}
1826 
1827 	if (oper == SUBSCRIPTION_REGISTRATION) {
1828 		return hs20_user_input_registration(ctx, session_id, 0);
1829 	}
1830 
1831 	debug_print(ctx, 1, "User session %s not in state for user input "
1832 		    "completion", session_id);
1833 	return NULL;
1834 }
1835 
1836 
hs20_cert_reenroll_complete(struct hs20_svc * ctx,const char * session_id)1837 static xml_node_t * hs20_cert_reenroll_complete(struct hs20_svc *ctx,
1838 						 const char *session_id)
1839 {
1840 	char *user, *realm, *cert;
1841 	char *status;
1842 	xml_namespace_t *ns;
1843 	xml_node_t *spp_node, *cred;
1844 	char buf[400];
1845 
1846 	user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
1847 	realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
1848 	cert = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
1849 	if (!user || !realm || !cert) {
1850 		debug_print(ctx, 1,
1851 			    "Could not find session info from DB for certificate reenrollment");
1852 		free(user);
1853 		free(realm);
1854 		free(cert);
1855 		return NULL;
1856 	}
1857 
1858 	cred = build_credential_cert(ctx, user, realm, cert);
1859 	if (!cred) {
1860 		debug_print(ctx, 1, "Could not build credential");
1861 		free(user);
1862 		free(realm);
1863 		free(cert);
1864 		return NULL;
1865 	}
1866 
1867 	status = "Remediation complete, request sppUpdateResponse";
1868 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1869 						NULL);
1870 	if (spp_node == NULL) {
1871 		debug_print(ctx, 1, "Could not build sppPostDevDataResponse");
1872 		free(user);
1873 		free(realm);
1874 		free(cert);
1875 		xml_node_free(ctx->xml, cred);
1876 		return NULL;
1877 	}
1878 
1879 	snprintf(buf, sizeof(buf),
1880 		 "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
1881 		 realm);
1882 
1883 	if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
1884 		debug_print(ctx, 1, "Could not add update node");
1885 		xml_node_free(ctx->xml, spp_node);
1886 		free(user);
1887 		free(realm);
1888 		free(cert);
1889 		return NULL;
1890 	}
1891 
1892 	hs20_eventlog_node(ctx, user, realm, session_id,
1893 			   "certificate reenrollment", cred);
1894 	xml_node_free(ctx->xml, cred);
1895 
1896 	free(user);
1897 	free(realm);
1898 	free(cert);
1899 	return spp_node;
1900 }
1901 
1902 
hs20_cert_enroll_completed(struct hs20_svc * ctx,const char * user,const char * realm,int dmacc,const char * session_id)1903 static xml_node_t * hs20_cert_enroll_completed(struct hs20_svc *ctx,
1904 					       const char *user,
1905 					       const char *realm, int dmacc,
1906 					       const char *session_id)
1907 {
1908 	char *val;
1909 	enum hs20_session_operation oper;
1910 
1911 	val = db_get_session_val(ctx, NULL, NULL, session_id, "operation");
1912 	if (val == NULL) {
1913 		debug_print(ctx, 1, "No session %s found to continue",
1914 			    session_id);
1915 		return NULL;
1916 	}
1917 	oper = atoi(val);
1918 	free(val);
1919 
1920 	if (oper == SUBSCRIPTION_REGISTRATION)
1921 		return hs20_user_input_registration(ctx, session_id, 1);
1922 	if (oper == CERT_REENROLL)
1923 		return hs20_cert_reenroll_complete(ctx, session_id);
1924 
1925 	debug_print(ctx, 1, "User session %s not in state for certificate "
1926 		    "enrollment completion", session_id);
1927 	return NULL;
1928 }
1929 
1930 
hs20_cert_enroll_failed(struct hs20_svc * ctx,const char * user,const char * realm,int dmacc,const char * session_id)1931 static xml_node_t * hs20_cert_enroll_failed(struct hs20_svc *ctx,
1932 					    const char *user,
1933 					    const char *realm, int dmacc,
1934 					    const char *session_id)
1935 {
1936 	char *val;
1937 	enum hs20_session_operation oper;
1938 	xml_node_t *spp_node, *node;
1939 	char *status;
1940 	xml_namespace_t *ns;
1941 
1942 	val = db_get_session_val(ctx, user, realm, session_id, "operation");
1943 	if (val == NULL) {
1944 		debug_print(ctx, 1, "No session %s found to continue",
1945 			    session_id);
1946 		return NULL;
1947 	}
1948 	oper = atoi(val);
1949 	free(val);
1950 
1951 	if (oper != SUBSCRIPTION_REGISTRATION) {
1952 		debug_print(ctx, 1, "User session %s not in state for "
1953 			    "enrollment failure", session_id);
1954 		return NULL;
1955 	}
1956 
1957 	status = "Error occurred";
1958 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1959 						NULL);
1960 	if (spp_node == NULL)
1961 		return NULL;
1962 	node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
1963 	xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
1964 			  "Credentials cannot be provisioned at this time");
1965 	db_remove_session(ctx, user, realm, session_id);
1966 
1967 	return spp_node;
1968 }
1969 
1970 
hs20_sim_provisioning(struct hs20_svc * ctx,const char * user,const char * realm,int dmacc,const char * session_id)1971 static xml_node_t * hs20_sim_provisioning(struct hs20_svc *ctx,
1972 					  const char *user,
1973 					  const char *realm, int dmacc,
1974 					  const char *session_id)
1975 {
1976 	xml_namespace_t *ns;
1977 	xml_node_t *spp_node, *node = NULL;
1978 	xml_node_t *pps, *tnds;
1979 	char buf[400];
1980 	char *str;
1981 	const char *status;
1982 	char dmacc_username[32];
1983 	char dmacc_password[32];
1984 	char *policy;
1985 	xml_node_t *policy_node = NULL;
1986 
1987 	if (!ctx->imsi) {
1988 		debug_print(ctx, 1, "IMSI not available for SIM provisioning");
1989 		return NULL;
1990 	}
1991 
1992 	if (new_password(dmacc_username, sizeof(dmacc_username)) < 0 ||
1993 	    new_password(dmacc_password, sizeof(dmacc_password)) < 0) {
1994 		debug_print(ctx, 1,
1995 			    "Failed to generate DMAcc username/password");
1996 		return NULL;
1997 	}
1998 
1999 	status = "Provisioning complete, request sppUpdateResponse";
2000 	spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
2001 						NULL);
2002 	if (!spp_node)
2003 		return NULL;
2004 
2005 	policy = db_get_osu_config_val(ctx, realm, "sim_policy");
2006 	if (policy) {
2007 		policy_node = read_policy_file(ctx, policy);
2008 		os_free(policy);
2009 		if (!policy_node) {
2010 			xml_node_free(ctx->xml, spp_node);
2011 			return NULL;
2012 		}
2013 		update_policy_update_uri(ctx, realm, policy_node);
2014 		node = get_node_uri(ctx->xml, policy_node,
2015 				    "Policy/PolicyUpdate");
2016 		if (node)
2017 			build_username_password(ctx, node, dmacc_username,
2018 						dmacc_password);
2019 	}
2020 
2021 	pps = build_pps(ctx, NULL, realm, NULL, NULL, 0, NULL, ctx->imsi,
2022 			dmacc_username, dmacc_password, policy_node);
2023 	if (!pps) {
2024 		xml_node_free(ctx->xml, spp_node);
2025 		return NULL;
2026 	}
2027 
2028 	debug_print(ctx, 1,
2029 		    "Request DB subscription registration on success notification");
2030 	if (!user || !user[0])
2031 		user = ctx->imsi;
2032 	db_add_session(ctx, user, realm, session_id, NULL, NULL,
2033 		       SUBSCRIPTION_REGISTRATION, NULL);
2034 	db_add_session_dmacc(ctx, session_id, dmacc_username, dmacc_password);
2035 	if (ctx->eap_method)
2036 		db_add_session_eap_method(ctx, session_id, ctx->eap_method);
2037 	if (ctx->id_hash)
2038 		db_add_session_id_hash(ctx, session_id, ctx->id_hash);
2039 	db_add_session_pps(ctx, user, realm, session_id, pps);
2040 
2041 	hs20_eventlog_node(ctx, user, realm, session_id,
2042 			   "new subscription", pps);
2043 
2044 	tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL);
2045 	xml_node_free(ctx->xml, pps);
2046 	if (!tnds) {
2047 		xml_node_free(ctx->xml, spp_node);
2048 		return NULL;
2049 	}
2050 
2051 	str = xml_node_to_str(ctx->xml, tnds);
2052 	xml_node_free(ctx->xml, tnds);
2053 	if (!str) {
2054 		xml_node_free(ctx->xml, spp_node);
2055 		return NULL;
2056 	}
2057 
2058 	node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str);
2059 	free(str);
2060 	snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm);
2061 	xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf);
2062 	xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS);
2063 
2064 	return spp_node;
2065 }
2066 
2067 
hs20_spp_post_dev_data(struct hs20_svc * ctx,xml_node_t * node,const char * user,const char * realm,const char * session_id,int dmacc)2068 static xml_node_t * hs20_spp_post_dev_data(struct hs20_svc *ctx,
2069 					   xml_node_t *node,
2070 					   const char *user,
2071 					   const char *realm,
2072 					   const char *session_id,
2073 					   int dmacc)
2074 {
2075 	const char *req_reason;
2076 	char *redirect_uri = NULL;
2077 	char *req_reason_buf = NULL;
2078 	char str[200];
2079 	xml_node_t *ret = NULL, *devinfo = NULL, *devdetail = NULL;
2080 	xml_node_t *mo, *macaddr;
2081 	char *version;
2082 	int valid;
2083 	char *supp, *pos;
2084 	char *err;
2085 	u8 wifi_mac_addr[ETH_ALEN];
2086 
2087 	version = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
2088 					     "sppVersion");
2089 	if (version == NULL || strstr(version, "1.0") == NULL) {
2090 		ret = build_post_dev_data_response(
2091 			ctx, NULL, session_id, "Error occurred",
2092 			"SPP version not supported");
2093 		hs20_eventlog_node(ctx, user, realm, session_id,
2094 				   "Unsupported sppVersion", ret);
2095 		xml_node_get_attr_value_free(ctx->xml, version);
2096 		return ret;
2097 	}
2098 	xml_node_get_attr_value_free(ctx->xml, version);
2099 
2100 	mo = get_node(ctx->xml, node, "supportedMOList");
2101 	if (mo == NULL) {
2102 		ret = build_post_dev_data_response(
2103 			ctx, NULL, session_id, "Error occurred",
2104 			"Other");
2105 		hs20_eventlog_node(ctx, user, realm, session_id,
2106 				   "No supportedMOList element", ret);
2107 		return ret;
2108 	}
2109 	supp = xml_node_get_text(ctx->xml, mo);
2110 	for (pos = supp; pos && *pos; pos++)
2111 		*pos = tolower(*pos);
2112 	if (supp == NULL ||
2113 	    strstr(supp, URN_OMA_DM_DEVINFO) == NULL ||
2114 	    strstr(supp, URN_OMA_DM_DEVDETAIL) == NULL ||
2115 	    strstr(supp, URN_HS20_PPS) == NULL) {
2116 		xml_node_get_text_free(ctx->xml, supp);
2117 		ret = build_post_dev_data_response(
2118 			ctx, NULL, session_id, "Error occurred",
2119 			"One or more mandatory MOs not supported");
2120 		hs20_eventlog_node(ctx, user, realm, session_id,
2121 				   "Unsupported MOs", ret);
2122 		return ret;
2123 	}
2124 	xml_node_get_text_free(ctx->xml, supp);
2125 
2126 	req_reason_buf = xml_node_get_attr_value(ctx->xml, node,
2127 						 "requestReason");
2128 	if (req_reason_buf == NULL) {
2129 		debug_print(ctx, 1, "No requestReason attribute");
2130 		return NULL;
2131 	}
2132 	req_reason = req_reason_buf;
2133 
2134 	redirect_uri = xml_node_get_attr_value(ctx->xml, node, "redirectURI");
2135 
2136 	debug_print(ctx, 1, "requestReason: %s  sessionID: %s  redirectURI: %s",
2137 		    req_reason, session_id, redirect_uri);
2138 	snprintf(str, sizeof(str), "sppPostDevData: requestReason=%s",
2139 		 req_reason);
2140 	hs20_eventlog(ctx, user, realm, session_id, str, NULL);
2141 
2142 	devinfo = spp_get_mo(ctx, node, URN_OMA_DM_DEVINFO, &valid, &err);
2143 	if (devinfo == NULL) {
2144 		ret = build_post_dev_data_response(ctx, NULL, session_id,
2145 						   "Error occurred", "Other");
2146 		hs20_eventlog_node(ctx, user, realm, session_id,
2147 				   "No DevInfo moContainer in sppPostDevData",
2148 				   ret);
2149 		os_free(err);
2150 		goto out;
2151 	}
2152 
2153 	hs20_eventlog_node(ctx, user, realm, session_id,
2154 			   "Received DevInfo MO", devinfo);
2155 	if (valid == 0) {
2156 		hs20_eventlog(ctx, user, realm, session_id,
2157 			      "OMA-DM DDF DTD validation errors in DevInfo MO",
2158 			      err);
2159 		ret = build_post_dev_data_response(ctx, NULL, session_id,
2160 						   "Error occurred", "Other");
2161 		os_free(err);
2162 		goto out;
2163 	}
2164 	os_free(err);
2165 	if (user)
2166 		db_update_mo(ctx, user, realm, "devinfo", devinfo);
2167 
2168 	devdetail = spp_get_mo(ctx, node, URN_OMA_DM_DEVDETAIL, &valid, &err);
2169 	if (devdetail == NULL) {
2170 		ret = build_post_dev_data_response(ctx, NULL, session_id,
2171 						   "Error occurred", "Other");
2172 		hs20_eventlog_node(ctx, user, realm, session_id,
2173 				   "No DevDetail moContainer in sppPostDevData",
2174 				   ret);
2175 		os_free(err);
2176 		goto out;
2177 	}
2178 
2179 	hs20_eventlog_node(ctx, user, realm, session_id,
2180 			   "Received DevDetail MO", devdetail);
2181 	if (valid == 0) {
2182 		hs20_eventlog(ctx, user, realm, session_id,
2183 			      "OMA-DM DDF DTD validation errors "
2184 			      "in DevDetail MO", err);
2185 		ret = build_post_dev_data_response(ctx, NULL, session_id,
2186 						   "Error occurred", "Other");
2187 		os_free(err);
2188 		goto out;
2189 	}
2190 	os_free(err);
2191 
2192 	os_memset(wifi_mac_addr, 0, ETH_ALEN);
2193 	macaddr = get_node(ctx->xml, devdetail,
2194 			   "Ext/org.wi-fi/Wi-Fi/Wi-FiMACAddress");
2195 	if (macaddr) {
2196 		char *addr, buf[50];
2197 
2198 		addr = xml_node_get_text(ctx->xml, macaddr);
2199 		if (addr && hwaddr_compact_aton(addr, wifi_mac_addr) == 0) {
2200 			snprintf(buf, sizeof(buf), "DevDetail MAC address: "
2201 				 MACSTR, MAC2STR(wifi_mac_addr));
2202 			hs20_eventlog(ctx, user, realm, session_id, buf, NULL);
2203 			xml_node_get_text_free(ctx->xml, addr);
2204 		} else {
2205 			hs20_eventlog(ctx, user, realm, session_id,
2206 				      "Could not extract MAC address from DevDetail",
2207 				      NULL);
2208 		}
2209 	} else {
2210 		hs20_eventlog(ctx, user, realm, session_id,
2211 			      "No MAC address in DevDetail", NULL);
2212 	}
2213 
2214 	if (user)
2215 		db_update_mo(ctx, user, realm, "devdetail", devdetail);
2216 
2217 	if (user)
2218 		mo = spp_get_mo(ctx, node, URN_HS20_PPS, &valid, &err);
2219 	else {
2220 		mo = NULL;
2221 		err = NULL;
2222 	}
2223 	if (user && mo) {
2224 		hs20_eventlog_node(ctx, user, realm, session_id,
2225 				   "Received PPS MO", mo);
2226 		if (valid == 0) {
2227 			hs20_eventlog(ctx, user, realm, session_id,
2228 				      "OMA-DM DDF DTD validation errors "
2229 				      "in PPS MO", err);
2230 			xml_node_get_attr_value_free(ctx->xml, redirect_uri);
2231 			os_free(err);
2232 			return build_post_dev_data_response(
2233 				ctx, NULL, session_id,
2234 				"Error occurred", "Other");
2235 		}
2236 		db_update_mo(ctx, user, realm, "pps", mo);
2237 		db_update_val(ctx, user, realm, "fetch_pps", "0", dmacc);
2238 		xml_node_free(ctx->xml, mo);
2239 	}
2240 	os_free(err);
2241 
2242 	if (user && !mo) {
2243 		char *fetch;
2244 		int fetch_pps;
2245 
2246 		fetch = db_get_val(ctx, user, realm, "fetch_pps", dmacc);
2247 		fetch_pps = fetch ? atoi(fetch) : 0;
2248 		free(fetch);
2249 
2250 		if (fetch_pps) {
2251 			enum hs20_session_operation oper;
2252 			if (strcasecmp(req_reason, "Subscription remediation")
2253 			    == 0)
2254 				oper = CONTINUE_SUBSCRIPTION_REMEDIATION;
2255 			else if (strcasecmp(req_reason, "Policy update") == 0)
2256 				oper = CONTINUE_POLICY_UPDATE;
2257 			else
2258 				oper = NO_OPERATION;
2259 			if (db_add_session(ctx, user, realm, session_id, NULL,
2260 					   NULL, oper, NULL) < 0)
2261 				goto out;
2262 
2263 			ret = spp_exec_upload_mo(ctx, session_id,
2264 						 URN_HS20_PPS);
2265 			hs20_eventlog_node(ctx, user, realm, session_id,
2266 					   "request PPS MO upload",
2267 					   ret);
2268 			goto out;
2269 		}
2270 	}
2271 
2272 	if (user && strcasecmp(req_reason, "MO upload") == 0) {
2273 		char *val = db_get_session_val(ctx, user, realm, session_id,
2274 					       "operation");
2275 		enum hs20_session_operation oper;
2276 		if (!val) {
2277 			debug_print(ctx, 1, "No session %s found to continue",
2278 				    session_id);
2279 			goto out;
2280 		}
2281 		oper = atoi(val);
2282 		free(val);
2283 		if (oper == CONTINUE_SUBSCRIPTION_REMEDIATION)
2284 			req_reason = "Subscription remediation";
2285 		else if (oper == CONTINUE_POLICY_UPDATE)
2286 			req_reason = "Policy update";
2287 		else {
2288 			debug_print(ctx, 1,
2289 				    "No pending operation in session %s",
2290 				    session_id);
2291 			goto out;
2292 		}
2293 	}
2294 
2295 	if (strcasecmp(req_reason, "Subscription registration") == 0) {
2296 		ret = hs20_subscription_registration(ctx, realm, session_id,
2297 						     redirect_uri,
2298 						     wifi_mac_addr);
2299 		hs20_eventlog_node(ctx, user, realm, session_id,
2300 				   "subscription registration response",
2301 				   ret);
2302 		goto out;
2303 	}
2304 	if (user && strcasecmp(req_reason, "Subscription remediation") == 0) {
2305 		ret = hs20_subscription_remediation(ctx, user, realm,
2306 						    session_id, dmacc,
2307 						    redirect_uri);
2308 		hs20_eventlog_node(ctx, user, realm, session_id,
2309 				   "subscription remediation response",
2310 				   ret);
2311 		goto out;
2312 	}
2313 	if (user && strcasecmp(req_reason, "Policy update") == 0) {
2314 		ret = hs20_policy_update(ctx, user, realm, session_id, dmacc);
2315 		hs20_eventlog_node(ctx, user, realm, session_id,
2316 				   "policy update response",
2317 				   ret);
2318 		goto out;
2319 	}
2320 
2321 	if (strcasecmp(req_reason, "User input completed") == 0) {
2322 		db_add_session_devinfo(ctx, session_id, devinfo);
2323 		db_add_session_devdetail(ctx, session_id, devdetail);
2324 		ret = hs20_user_input_complete(ctx, user, realm, dmacc,
2325 					       session_id);
2326 		hs20_eventlog_node(ctx, user, realm, session_id,
2327 				   "user input completed response", ret);
2328 		goto out;
2329 	}
2330 
2331 	if (strcasecmp(req_reason, "Certificate enrollment completed") == 0) {
2332 		ret = hs20_cert_enroll_completed(ctx, user, realm, dmacc,
2333 						 session_id);
2334 		hs20_eventlog_node(ctx, user, realm, session_id,
2335 				   "certificate enrollment response", ret);
2336 		goto out;
2337 	}
2338 
2339 	if (strcasecmp(req_reason, "Certificate enrollment failed") == 0) {
2340 		ret = hs20_cert_enroll_failed(ctx, user, realm, dmacc,
2341 					      session_id);
2342 		hs20_eventlog_node(ctx, user, realm, session_id,
2343 				   "certificate enrollment failed response",
2344 				   ret);
2345 		goto out;
2346 	}
2347 
2348 	if (strcasecmp(req_reason, "Subscription provisioning") == 0) {
2349 		ret = hs20_sim_provisioning(ctx, user, realm, dmacc,
2350 					    session_id);
2351 		hs20_eventlog_node(ctx, user, realm, session_id,
2352 				   "subscription provisioning response",
2353 				   ret);
2354 		goto out;
2355 	}
2356 
2357 	debug_print(ctx, 1, "Unsupported requestReason '%s' user '%s'",
2358 		    req_reason, user);
2359 out:
2360 	xml_node_get_attr_value_free(ctx->xml, req_reason_buf);
2361 	xml_node_get_attr_value_free(ctx->xml, redirect_uri);
2362 	if (devinfo)
2363 		xml_node_free(ctx->xml, devinfo);
2364 	if (devdetail)
2365 		xml_node_free(ctx->xml, devdetail);
2366 	return ret;
2367 }
2368 
2369 
build_spp_exchange_complete(struct hs20_svc * ctx,const char * session_id,const char * status,const char * error_code)2370 static xml_node_t * build_spp_exchange_complete(struct hs20_svc *ctx,
2371 						const char *session_id,
2372 						const char *status,
2373 						const char *error_code)
2374 {
2375 	xml_namespace_t *ns;
2376 	xml_node_t *spp_node, *node;
2377 
2378 	spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
2379 					"sppExchangeComplete");
2380 
2381 
2382 	xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
2383 	xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
2384 	xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
2385 
2386 	if (error_code) {
2387 		node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
2388 		xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
2389 				  error_code);
2390 	}
2391 
2392 	return spp_node;
2393 }
2394 
2395 
add_subscription(struct hs20_svc * ctx,const char * session_id)2396 static int add_subscription(struct hs20_svc *ctx, const char *session_id)
2397 {
2398 	char *user, *realm, *pw, *pw_mm, *pps, *str;
2399 	char *osu_user, *osu_password, *eap_method;
2400 	char *policy = NULL;
2401 	char *sql;
2402 	int ret = -1;
2403 	char *free_account;
2404 	int free_acc;
2405 	char *type;
2406 	int cert = 0;
2407 	char *cert_pem, *fingerprint;
2408 	const char *method;
2409 
2410 	user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
2411 	realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
2412 	pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
2413 	pw_mm = db_get_session_val(ctx, NULL, NULL, session_id,
2414 				   "machine_managed");
2415 	pps = db_get_session_val(ctx, NULL, NULL, session_id, "pps");
2416 	cert_pem = db_get_session_val(ctx, NULL, NULL, session_id, "cert_pem");
2417 	fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
2418 	type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
2419 	if (type && strcmp(type, "cert") == 0)
2420 		cert = 1;
2421 	free(type);
2422 	osu_user = db_get_session_val(ctx, NULL, NULL, session_id, "osu_user");
2423 	osu_password = db_get_session_val(ctx, NULL, NULL, session_id,
2424 					  "osu_password");
2425 	eap_method = db_get_session_val(ctx, NULL, NULL, session_id,
2426 					"eap_method");
2427 
2428 	if (!user || !realm || !pw) {
2429 		debug_print(ctx, 1, "Could not find session info from DB for "
2430 			    "the new subscription");
2431 		goto out;
2432 	}
2433 
2434 	free_account = db_get_osu_config_val(ctx, realm, "free_account");
2435 	free_acc = free_account && strcmp(free_account, user) == 0;
2436 	free(free_account);
2437 
2438 	policy = db_get_osu_config_val(ctx, realm, "sim_policy");
2439 
2440 	debug_print(ctx, 1,
2441 		    "New subscription: user='%s' realm='%s' free_acc=%d",
2442 		    user, realm, free_acc);
2443 	debug_print(ctx, 1, "New subscription: pps='%s'", pps);
2444 
2445 	sql = sqlite3_mprintf("UPDATE eventlog SET user=%Q, realm=%Q WHERE "
2446 			      "sessionid=%Q AND (user='' OR user IS NULL)",
2447 			      user, realm, session_id);
2448 	if (sql) {
2449 		debug_print(ctx, 1, "DB: %s", sql);
2450 		if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
2451 			debug_print(ctx, 1, "Failed to update eventlog in "
2452 				    "sqlite database: %s",
2453 				    sqlite3_errmsg(ctx->db));
2454 		}
2455 		sqlite3_free(sql);
2456 	}
2457 
2458 	if (free_acc) {
2459 		hs20_eventlog(ctx, user, realm, session_id,
2460 			      "completed shared free account registration",
2461 			      NULL);
2462 		ret = 0;
2463 		goto out;
2464 	}
2465 
2466 	str = db_get_session_val(ctx, NULL, NULL, session_id, "mac_addr");
2467 
2468 	if (eap_method && eap_method[0])
2469 		method = eap_method;
2470 	else
2471 		method = cert ? "TLS" : "TTLS-MSCHAPV2";
2472 	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)",
2473 			      user, realm, cert ? 0 : 1,
2474 			      method,
2475 			      fingerprint ? fingerprint : "",
2476 			      cert_pem ? cert_pem : "",
2477 			      pw_mm && atoi(pw_mm) ? 1 : 0,
2478 			      str ? str : "",
2479 			      osu_user ? osu_user : "",
2480 			      osu_password ? osu_password : "",
2481 			      policy ? policy : "");
2482 	free(str);
2483 	if (sql == NULL)
2484 		goto out;
2485 	debug_print(ctx, 1, "DB: %s", sql);
2486 	if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
2487 		debug_print(ctx, 1, "Failed to add user in sqlite database: %s",
2488 			    sqlite3_errmsg(ctx->db));
2489 		sqlite3_free(sql);
2490 		goto out;
2491 	}
2492 	sqlite3_free(sql);
2493 
2494 	if (cert)
2495 		ret = 0;
2496 	else
2497 		ret = update_password(ctx, user, realm, pw, 0);
2498 	if (ret < 0) {
2499 		sql = sqlite3_mprintf("DELETE FROM users WHERE identity=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
2500 				      user, realm);
2501 		if (sql) {
2502 			debug_print(ctx, 1, "DB: %s", sql);
2503 			sqlite3_exec(ctx->db, sql, NULL, NULL, NULL);
2504 			sqlite3_free(sql);
2505 		}
2506 	}
2507 
2508 	if (pps)
2509 		db_update_mo_str(ctx, user, realm, "pps", pps);
2510 
2511 	str = db_get_session_val(ctx, NULL, NULL, session_id, "devinfo");
2512 	if (str) {
2513 		db_update_mo_str(ctx, user, realm, "devinfo", str);
2514 		free(str);
2515 	}
2516 
2517 	str = db_get_session_val(ctx, NULL, NULL, session_id, "devdetail");
2518 	if (str) {
2519 		db_update_mo_str(ctx, user, realm, "devdetail", str);
2520 		free(str);
2521 	}
2522 
2523 	if (cert && user) {
2524 		const char *serialnum;
2525 
2526 		str = db_get_session_val(ctx, NULL, NULL, session_id,
2527 					 "mac_addr");
2528 
2529 		if (os_strncmp(user, "cert-", 5) == 0)
2530 			serialnum = user + 5;
2531 		else
2532 			serialnum = "";
2533 		sql = sqlite3_mprintf("INSERT OR REPLACE INTO cert_enroll (mac_addr,user,realm,serialnum) VALUES(%Q,%Q,%Q,%Q)",
2534 				      str ? str : "", user, realm ? realm : "",
2535 				      serialnum);
2536 		free(str);
2537 		if (sql) {
2538 			debug_print(ctx, 1, "DB: %s", sql);
2539 			if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) !=
2540 			    SQLITE_OK) {
2541 				debug_print(ctx, 1,
2542 					    "Failed to add cert_enroll entry into sqlite database: %s",
2543 					    sqlite3_errmsg(ctx->db));
2544 			}
2545 			sqlite3_free(sql);
2546 		}
2547 	}
2548 
2549 	str = db_get_session_val(ctx, NULL, NULL, session_id,
2550 				 "mobile_identifier_hash");
2551 	if (str) {
2552 		sql = sqlite3_mprintf("DELETE FROM sim_provisioning WHERE mobile_identifier_hash=%Q",
2553 				      str);
2554 		if (sql) {
2555 			debug_print(ctx, 1, "DB: %s", sql);
2556 			if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) !=
2557 			    SQLITE_OK) {
2558 				debug_print(ctx, 1,
2559 					    "Failed to delete pending sim_provisioning entry: %s",
2560 					    sqlite3_errmsg(ctx->db));
2561 			}
2562 			sqlite3_free(sql);
2563 		}
2564 		os_free(str);
2565 	}
2566 
2567 	if (ret == 0) {
2568 		hs20_eventlog(ctx, user, realm, session_id,
2569 			      "completed subscription registration", NULL);
2570 	}
2571 
2572 out:
2573 	free(user);
2574 	free(realm);
2575 	free(pw);
2576 	free(pw_mm);
2577 	free(pps);
2578 	free(cert_pem);
2579 	free(fingerprint);
2580 	free(osu_user);
2581 	free(osu_password);
2582 	free(eap_method);
2583 	os_free(policy);
2584 	return ret;
2585 }
2586 
2587 
hs20_spp_update_response(struct hs20_svc * ctx,xml_node_t * node,const char * user,const char * realm,const char * session_id,int dmacc)2588 static xml_node_t * hs20_spp_update_response(struct hs20_svc *ctx,
2589 					     xml_node_t *node,
2590 					     const char *user,
2591 					     const char *realm,
2592 					     const char *session_id,
2593 					     int dmacc)
2594 {
2595 	char *status;
2596 	xml_node_t *ret;
2597 	char *val;
2598 	enum hs20_session_operation oper;
2599 
2600 	status = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
2601 					    "sppStatus");
2602 	if (status == NULL) {
2603 		debug_print(ctx, 1, "No sppStatus attribute");
2604 		return NULL;
2605 	}
2606 
2607 	debug_print(ctx, 1, "sppUpdateResponse: sppStatus: %s  sessionID: %s",
2608 		    status, session_id);
2609 
2610 	val = db_get_session_val(ctx, NULL, NULL, session_id, "operation");
2611 	if (!val) {
2612 		debug_print(ctx, 1,
2613 			    "No session active for sessionID: %s",
2614 			    session_id);
2615 		oper = NO_OPERATION;
2616 	} else
2617 		oper = atoi(val);
2618 
2619 	if (strcasecmp(status, "OK") == 0) {
2620 		char *new_pw = NULL;
2621 
2622 		xml_node_get_attr_value_free(ctx->xml, status);
2623 
2624 		if (oper == USER_REMEDIATION) {
2625 			new_pw = db_get_session_val(ctx, user, realm,
2626 						    session_id, "password");
2627 			if (new_pw == NULL || strlen(new_pw) == 0) {
2628 				free(new_pw);
2629 				ret = build_spp_exchange_complete(
2630 					ctx, session_id, "Error occurred",
2631 					"Other");
2632 				hs20_eventlog_node(ctx, user, realm,
2633 						   session_id, "No password "
2634 						   "had been assigned for "
2635 						   "session", ret);
2636 				db_remove_session(ctx, user, realm, session_id);
2637 				return ret;
2638 			}
2639 			oper = UPDATE_PASSWORD;
2640 		}
2641 		if (oper == UPDATE_PASSWORD) {
2642 			if (!new_pw) {
2643 				new_pw = db_get_session_val(ctx, user, realm,
2644 							    session_id,
2645 							    "password");
2646 				if (!new_pw) {
2647 					db_remove_session(ctx, user, realm,
2648 							  session_id);
2649 					return NULL;
2650 				}
2651 			}
2652 			debug_print(ctx, 1, "Update user '%s' password in DB",
2653 				    user);
2654 			if (update_password(ctx, user, realm, new_pw, dmacc) <
2655 			    0) {
2656 				debug_print(ctx, 1, "Failed to update user "
2657 					    "'%s' password in DB", user);
2658 				ret = build_spp_exchange_complete(
2659 					ctx, session_id, "Error occurred",
2660 					"Other");
2661 				hs20_eventlog_node(ctx, user, realm,
2662 						   session_id, "Failed to "
2663 						   "update database", ret);
2664 				db_remove_session(ctx, user, realm, session_id);
2665 				return ret;
2666 			}
2667 			hs20_eventlog(ctx, user, realm,
2668 				      session_id, "Updated user password "
2669 				      "in database", NULL);
2670 		}
2671 		if (oper == CLEAR_REMEDIATION) {
2672 			debug_print(ctx, 1,
2673 				    "Clear remediation requirement for user '%s' in DB",
2674 				    user);
2675 			if (clear_remediation(ctx, user, realm, dmacc) < 0) {
2676 				debug_print(ctx, 1,
2677 					    "Failed to clear remediation requirement for user '%s' in DB",
2678 					    user);
2679 				ret = build_spp_exchange_complete(
2680 					ctx, session_id, "Error occurred",
2681 					"Other");
2682 				hs20_eventlog_node(ctx, user, realm,
2683 						   session_id,
2684 						   "Failed to update database",
2685 						   ret);
2686 				db_remove_session(ctx, user, realm, session_id);
2687 				return ret;
2688 			}
2689 			hs20_eventlog(ctx, user, realm,
2690 				      session_id,
2691 				      "Cleared remediation requirement in database",
2692 				      NULL);
2693 		}
2694 		if (oper == SUBSCRIPTION_REGISTRATION) {
2695 			if (add_subscription(ctx, session_id) < 0) {
2696 				debug_print(ctx, 1, "Failed to add "
2697 					    "subscription into DB");
2698 				ret = build_spp_exchange_complete(
2699 					ctx, session_id, "Error occurred",
2700 					"Other");
2701 				hs20_eventlog_node(ctx, user, realm,
2702 						   session_id, "Failed to "
2703 						   "update database", ret);
2704 				db_remove_session(ctx, user, realm, session_id);
2705 				return ret;
2706 			}
2707 		}
2708 		if (oper == POLICY_REMEDIATION || oper == POLICY_UPDATE) {
2709 			char *val;
2710 			val = db_get_val(ctx, user, realm, "remediation",
2711 					 dmacc);
2712 			if (val && strcmp(val, "policy") == 0)
2713 				db_update_val(ctx, user, realm, "remediation",
2714 					      "", dmacc);
2715 			free(val);
2716 		}
2717 		if (oper == POLICY_UPDATE)
2718 			db_update_val(ctx, user, realm, "polupd_done", "1",
2719 				      dmacc);
2720 		if (oper == CERT_REENROLL) {
2721 			char *new_user;
2722 			char event[200];
2723 
2724 			new_user = db_get_session_val(ctx, NULL, NULL,
2725 						      session_id, "user");
2726 			if (!new_user) {
2727 				debug_print(ctx, 1,
2728 					    "Failed to find new user name (cert-serialnum)");
2729 				ret = build_spp_exchange_complete(
2730 					ctx, session_id, "Error occurred",
2731 					"Other");
2732 				hs20_eventlog_node(ctx, user, realm,
2733 						   session_id,
2734 						   "Failed to find new user name (cert reenroll)",
2735 						   ret);
2736 				db_remove_session(ctx, NULL, NULL, session_id);
2737 				return ret;
2738 			}
2739 
2740 			debug_print(ctx, 1,
2741 				    "Update certificate user entry to use the new serial number (old=%s new=%s)",
2742 				    user, new_user);
2743 			os_snprintf(event, sizeof(event), "renamed user to: %s",
2744 				    new_user);
2745 			hs20_eventlog(ctx, user, realm, session_id, event,
2746 				      NULL);
2747 
2748 			if (db_update_val(ctx, user, realm, "identity",
2749 					  new_user, 0) < 0 ||
2750 			    db_update_val(ctx, new_user, realm, "remediation",
2751 					  "", 0) < 0) {
2752 				debug_print(ctx, 1,
2753 					    "Failed to update user name (cert-serialnum)");
2754 				ret = build_spp_exchange_complete(
2755 					ctx, session_id, "Error occurred",
2756 					"Other");
2757 				hs20_eventlog_node(ctx, user, realm,
2758 						   session_id,
2759 						   "Failed to update user name (cert reenroll)",
2760 						   ret);
2761 				db_remove_session(ctx, NULL, NULL, session_id);
2762 				os_free(new_user);
2763 				return ret;
2764 			}
2765 
2766 			os_free(new_user);
2767 		}
2768 		ret = build_spp_exchange_complete(
2769 			ctx, session_id,
2770 			"Exchange complete, release TLS connection", NULL);
2771 		hs20_eventlog_node(ctx, user, realm, session_id,
2772 				   "Exchange completed", ret);
2773 		db_remove_session(ctx, NULL, NULL, session_id);
2774 		return ret;
2775 	}
2776 
2777 	ret = build_spp_exchange_complete(ctx, session_id, "Error occurred",
2778 					  "Other");
2779 	hs20_eventlog_node(ctx, user, realm, session_id, "Error occurred", ret);
2780 	db_remove_session(ctx, user, realm, session_id);
2781 	xml_node_get_attr_value_free(ctx->xml, status);
2782 	return ret;
2783 }
2784 
2785 
2786 #define SPP_SESSION_ID_LEN 16
2787 
gen_spp_session_id(void)2788 static char * gen_spp_session_id(void)
2789 {
2790 	FILE *f;
2791 	int i;
2792 	char *session;
2793 
2794 	session = os_malloc(SPP_SESSION_ID_LEN * 2 + 1);
2795 	if (session == NULL)
2796 		return NULL;
2797 
2798 	f = fopen("/dev/urandom", "r");
2799 	if (f == NULL) {
2800 		os_free(session);
2801 		return NULL;
2802 	}
2803 	for (i = 0; i < SPP_SESSION_ID_LEN; i++)
2804 		os_snprintf(session + i * 2, 3, "%02x", fgetc(f));
2805 
2806 	fclose(f);
2807 	return session;
2808 }
2809 
hs20_spp_server_process(struct hs20_svc * ctx,xml_node_t * node,const char * auth_user,const char * auth_realm,int dmacc)2810 xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node,
2811 				     const char *auth_user,
2812 				     const char *auth_realm, int dmacc)
2813 {
2814 	xml_node_t *ret = NULL;
2815 	char *session_id;
2816 	const char *op_name;
2817 	char *xml_err;
2818 	char fname[200];
2819 
2820 	debug_dump_node(ctx, "received request", node);
2821 
2822 	if (!dmacc && auth_user && auth_realm) {
2823 		char *real;
2824 		real = db_get_val(ctx, auth_user, auth_realm, "identity", 0);
2825 		if (!real) {
2826 			real = db_get_val(ctx, auth_user, auth_realm,
2827 					  "identity", 1);
2828 			if (real)
2829 				dmacc = 1;
2830 		}
2831 		os_free(real);
2832 	}
2833 
2834 	snprintf(fname, sizeof(fname), "%s/spp/spp.xsd", ctx->root_dir);
2835 	if (xml_validate(ctx->xml, node, fname, &xml_err) < 0) {
2836 		/*
2837 		 * We may not be able to extract the sessionID from invalid
2838 		 * input, but well, we can try.
2839 		 */
2840 		session_id = xml_node_get_attr_value_ns(ctx->xml, node,
2841 							SPP_NS_URI,
2842 							"sessionID");
2843 		debug_print(ctx, 1,
2844 			    "SPP message failed validation, xsd file: %s  xml-error: %s",
2845 			    fname, xml_err);
2846 		hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2847 				   "SPP message failed validation", node);
2848 		hs20_eventlog(ctx, auth_user, auth_realm, session_id,
2849 			      "Validation errors", xml_err);
2850 		os_free(xml_err);
2851 		xml_node_get_attr_value_free(ctx->xml, session_id);
2852 		/* TODO: what to return here? */
2853 		ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2854 					   "SppValidationError");
2855 		return ret;
2856 	}
2857 
2858 	session_id = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
2859 						"sessionID");
2860 	if (session_id) {
2861 		char *tmp;
2862 		debug_print(ctx, 1, "Received sessionID %s", session_id);
2863 		tmp = os_strdup(session_id);
2864 		xml_node_get_attr_value_free(ctx->xml, session_id);
2865 		if (tmp == NULL)
2866 			return NULL;
2867 		session_id = tmp;
2868 	} else {
2869 		session_id = gen_spp_session_id();
2870 		if (session_id == NULL) {
2871 			debug_print(ctx, 1, "Failed to generate sessionID");
2872 			return NULL;
2873 		}
2874 		debug_print(ctx, 1, "Generated sessionID %s", session_id);
2875 	}
2876 
2877 	op_name = xml_node_get_localname(ctx->xml, node);
2878 	if (op_name == NULL) {
2879 		debug_print(ctx, 1, "Could not get op_name");
2880 		return NULL;
2881 	}
2882 
2883 	if (strcmp(op_name, "sppPostDevData") == 0) {
2884 		hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2885 				   "sppPostDevData received and validated",
2886 				   node);
2887 		ret = hs20_spp_post_dev_data(ctx, node, auth_user, auth_realm,
2888 					     session_id, dmacc);
2889 	} else if (strcmp(op_name, "sppUpdateResponse") == 0) {
2890 		hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2891 				   "sppUpdateResponse received and validated",
2892 				   node);
2893 		ret = hs20_spp_update_response(ctx, node, auth_user,
2894 					       auth_realm, session_id, dmacc);
2895 	} else {
2896 		hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2897 				   "Unsupported SPP message received and "
2898 				   "validated", node);
2899 		debug_print(ctx, 1, "Unsupported operation '%s'", op_name);
2900 		/* TODO: what to return here? */
2901 		ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2902 					   "SppUnknownCommandError");
2903 	}
2904 	os_free(session_id);
2905 
2906 	if (ret == NULL) {
2907 		/* TODO: what to return here? */
2908 		ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2909 					   "SppInternalError");
2910 	}
2911 
2912 	return ret;
2913 }
2914 
2915 
hs20_spp_server_init(struct hs20_svc * ctx)2916 int hs20_spp_server_init(struct hs20_svc *ctx)
2917 {
2918 	char fname[200];
2919 	ctx->db = NULL;
2920 	snprintf(fname, sizeof(fname), "%s/AS/DB/eap_user.db", ctx->root_dir);
2921 	if (sqlite3_open(fname, &ctx->db)) {
2922 		printf("Failed to open sqlite database: %s\n",
2923 		       sqlite3_errmsg(ctx->db));
2924 		sqlite3_close(ctx->db);
2925 		return -1;
2926 	}
2927 
2928 	return 0;
2929 }
2930 
2931 
hs20_spp_server_deinit(struct hs20_svc * ctx)2932 void hs20_spp_server_deinit(struct hs20_svc *ctx)
2933 {
2934 	sqlite3_close(ctx->db);
2935 	ctx->db = NULL;
2936 }
2937