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