• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 		db_add_session_devinfo(ctx, session_id, devinfo);
1827 		db_add_session_devdetail(ctx, session_id, devdetail);
1828 		ret = hs20_user_input_complete(ctx, user, realm, dmacc,
1829 					       session_id);
1830 		hs20_eventlog_node(ctx, user, realm, session_id,
1831 				   "user input completed response", ret);
1832 		goto out;
1833 	}
1834 
1835 	if (strcasecmp(req_reason, "Certificate enrollment completed") == 0) {
1836 		ret = hs20_cert_enroll_completed(ctx, user, realm, dmacc,
1837 						 session_id);
1838 		hs20_eventlog_node(ctx, user, realm, session_id,
1839 				   "certificate enrollment response", ret);
1840 		goto out;
1841 	}
1842 
1843 	if (strcasecmp(req_reason, "Certificate enrollment failed") == 0) {
1844 		ret = hs20_cert_enroll_failed(ctx, user, realm, dmacc,
1845 					      session_id);
1846 		hs20_eventlog_node(ctx, user, realm, session_id,
1847 				   "certificate enrollment failed response",
1848 				   ret);
1849 		goto out;
1850 	}
1851 
1852 	debug_print(ctx, 1, "Unsupported requestReason '%s' user '%s'",
1853 		    req_reason, user);
1854 out:
1855 	xml_node_get_attr_value_free(ctx->xml, req_reason_buf);
1856 	xml_node_get_attr_value_free(ctx->xml, redirect_uri);
1857 	if (devinfo)
1858 		xml_node_free(ctx->xml, devinfo);
1859 	if (devdetail)
1860 		xml_node_free(ctx->xml, devdetail);
1861 	return ret;
1862 }
1863 
1864 
build_spp_exchange_complete(struct hs20_svc * ctx,const char * session_id,const char * status,const char * error_code)1865 static xml_node_t * build_spp_exchange_complete(struct hs20_svc *ctx,
1866 						const char *session_id,
1867 						const char *status,
1868 						const char *error_code)
1869 {
1870 	xml_namespace_t *ns;
1871 	xml_node_t *spp_node, *node;
1872 
1873 	spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
1874 					"sppExchangeComplete");
1875 
1876 
1877 	xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
1878 	xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
1879 	xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
1880 
1881 	if (error_code) {
1882 		node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
1883 		xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
1884 				  error_code);
1885 	}
1886 
1887 	return spp_node;
1888 }
1889 
1890 
add_subscription(struct hs20_svc * ctx,const char * session_id)1891 static int add_subscription(struct hs20_svc *ctx, const char *session_id)
1892 {
1893 	char *user, *realm, *pw, *pw_mm, *pps, *str;
1894 	char *sql;
1895 	int ret = -1;
1896 	char *free_account;
1897 	int free_acc;
1898 	char *type;
1899 	int cert = 0;
1900 	char *cert_pem, *fingerprint;
1901 
1902 	user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
1903 	realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
1904 	pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
1905 	pw_mm = db_get_session_val(ctx, NULL, NULL, session_id,
1906 				   "machine_managed");
1907 	pps = db_get_session_val(ctx, NULL, NULL, session_id, "pps");
1908 	cert_pem = db_get_session_val(ctx, NULL, NULL, session_id, "cert_pem");
1909 	fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
1910 	type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
1911 	if (type && strcmp(type, "cert") == 0)
1912 		cert = 1;
1913 	free(type);
1914 
1915 	if (!user || !realm || !pw) {
1916 		debug_print(ctx, 1, "Could not find session info from DB for "
1917 			    "the new subscription");
1918 		goto out;
1919 	}
1920 
1921 	free_account = db_get_osu_config_val(ctx, realm, "free_account");
1922 	free_acc = free_account && strcmp(free_account, user) == 0;
1923 	free(free_account);
1924 
1925 	debug_print(ctx, 1,
1926 		    "New subscription: user='%s' realm='%s' free_acc=%d",
1927 		    user, realm, free_acc);
1928 	debug_print(ctx, 1, "New subscription: pps='%s'", pps);
1929 
1930 	sql = sqlite3_mprintf("UPDATE eventlog SET user=%Q, realm=%Q WHERE "
1931 			      "sessionid=%Q AND (user='' OR user IS NULL)",
1932 			      user, realm, session_id);
1933 	if (sql) {
1934 		debug_print(ctx, 1, "DB: %s", sql);
1935 		if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
1936 			debug_print(ctx, 1, "Failed to update eventlog in "
1937 				    "sqlite database: %s",
1938 				    sqlite3_errmsg(ctx->db));
1939 		}
1940 		sqlite3_free(sql);
1941 	}
1942 
1943 	if (free_acc) {
1944 		hs20_eventlog(ctx, user, realm, session_id,
1945 			      "completed shared free account registration",
1946 			      NULL);
1947 		ret = 0;
1948 		goto out;
1949 	}
1950 
1951 	sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,"
1952 			      "methods,cert,cert_pem,machine_managed) VALUES "
1953 			      "(%Q,%Q,1,%Q,%Q,%Q,%d)",
1954 			      user, realm, cert ? "TLS" : "TTLS-MSCHAPV2",
1955 			      fingerprint ? fingerprint : "",
1956 			      cert_pem ? cert_pem : "",
1957 			      pw_mm && atoi(pw_mm) ? 1 : 0);
1958 	if (sql == NULL)
1959 		goto out;
1960 	debug_print(ctx, 1, "DB: %s", sql);
1961 	if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
1962 		debug_print(ctx, 1, "Failed to add user in sqlite database: %s",
1963 			    sqlite3_errmsg(ctx->db));
1964 		sqlite3_free(sql);
1965 		goto out;
1966 	}
1967 	sqlite3_free(sql);
1968 
1969 	if (cert)
1970 		ret = 0;
1971 	else
1972 		ret = update_password(ctx, user, realm, pw, 0);
1973 	if (ret < 0) {
1974 		sql = sqlite3_mprintf("DELETE FROM users WHERE identity=%Q AND "
1975 				      "realm=%Q AND phase2=1",
1976 				      user, realm);
1977 		if (sql) {
1978 			debug_print(ctx, 1, "DB: %s", sql);
1979 			sqlite3_exec(ctx->db, sql, NULL, NULL, NULL);
1980 			sqlite3_free(sql);
1981 		}
1982 	}
1983 
1984 	if (pps)
1985 		db_update_mo_str(ctx, user, realm, "pps", pps);
1986 
1987 	str = db_get_session_val(ctx, NULL, NULL, session_id, "devinfo");
1988 	if (str) {
1989 		db_update_mo_str(ctx, user, realm, "devinfo", str);
1990 		free(str);
1991 	}
1992 
1993 	str = db_get_session_val(ctx, NULL, NULL, session_id, "devdetail");
1994 	if (str) {
1995 		db_update_mo_str(ctx, user, realm, "devdetail", str);
1996 		free(str);
1997 	}
1998 
1999 	if (ret == 0) {
2000 		hs20_eventlog(ctx, user, realm, session_id,
2001 			      "completed subscription registration", NULL);
2002 	}
2003 
2004 out:
2005 	free(user);
2006 	free(realm);
2007 	free(pw);
2008 	free(pw_mm);
2009 	free(pps);
2010 	free(cert_pem);
2011 	free(fingerprint);
2012 	return ret;
2013 }
2014 
2015 
hs20_spp_update_response(struct hs20_svc * ctx,xml_node_t * node,const char * user,const char * realm,const char * session_id,int dmacc)2016 static xml_node_t * hs20_spp_update_response(struct hs20_svc *ctx,
2017 					     xml_node_t *node,
2018 					     const char *user,
2019 					     const char *realm,
2020 					     const char *session_id,
2021 					     int dmacc)
2022 {
2023 	char *status;
2024 	xml_node_t *ret;
2025 	char *val;
2026 	enum hs20_session_operation oper;
2027 
2028 	status = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
2029 					    "sppStatus");
2030 	if (status == NULL) {
2031 		debug_print(ctx, 1, "No sppStatus attribute");
2032 		return NULL;
2033 	}
2034 
2035 	debug_print(ctx, 1, "sppUpdateResponse: sppStatus: %s  sessionID: %s",
2036 		    status, session_id);
2037 
2038 	val = db_get_session_val(ctx, user, realm, session_id, "operation");
2039 	if (!val) {
2040 		debug_print(ctx, 1,
2041 			    "No session active for user: %s  sessionID: %s",
2042 			    user, session_id);
2043 		oper = NO_OPERATION;
2044 	} else
2045 		oper = atoi(val);
2046 
2047 	if (strcasecmp(status, "OK") == 0) {
2048 		char *new_pw = NULL;
2049 
2050 		xml_node_get_attr_value_free(ctx->xml, status);
2051 
2052 		if (oper == USER_REMEDIATION) {
2053 			new_pw = db_get_session_val(ctx, user, realm,
2054 						    session_id, "password");
2055 			if (new_pw == NULL || strlen(new_pw) == 0) {
2056 				free(new_pw);
2057 				ret = build_spp_exchange_complete(
2058 					ctx, session_id, "Error occurred",
2059 					"Other");
2060 				hs20_eventlog_node(ctx, user, realm,
2061 						   session_id, "No password "
2062 						   "had been assigned for "
2063 						   "session", ret);
2064 				db_remove_session(ctx, user, realm, session_id);
2065 				return ret;
2066 			}
2067 			oper = UPDATE_PASSWORD;
2068 		}
2069 		if (oper == UPDATE_PASSWORD) {
2070 			if (!new_pw) {
2071 				new_pw = db_get_session_val(ctx, user, realm,
2072 							    session_id,
2073 							    "password");
2074 				if (!new_pw) {
2075 					db_remove_session(ctx, user, realm,
2076 							  session_id);
2077 					return NULL;
2078 				}
2079 			}
2080 			debug_print(ctx, 1, "Update user '%s' password in DB",
2081 				    user);
2082 			if (update_password(ctx, user, realm, new_pw, dmacc) <
2083 			    0) {
2084 				debug_print(ctx, 1, "Failed to update user "
2085 					    "'%s' password in DB", user);
2086 				ret = build_spp_exchange_complete(
2087 					ctx, session_id, "Error occurred",
2088 					"Other");
2089 				hs20_eventlog_node(ctx, user, realm,
2090 						   session_id, "Failed to "
2091 						   "update database", ret);
2092 				db_remove_session(ctx, user, realm, session_id);
2093 				return ret;
2094 			}
2095 			hs20_eventlog(ctx, user, realm,
2096 				      session_id, "Updated user password "
2097 				      "in database", NULL);
2098 		}
2099 		if (oper == SUBSCRIPTION_REGISTRATION) {
2100 			if (add_subscription(ctx, session_id) < 0) {
2101 				debug_print(ctx, 1, "Failed to add "
2102 					    "subscription into DB");
2103 				ret = build_spp_exchange_complete(
2104 					ctx, session_id, "Error occurred",
2105 					"Other");
2106 				hs20_eventlog_node(ctx, user, realm,
2107 						   session_id, "Failed to "
2108 						   "update database", ret);
2109 				db_remove_session(ctx, user, realm, session_id);
2110 				return ret;
2111 			}
2112 		}
2113 		if (oper == POLICY_REMEDIATION || oper == POLICY_UPDATE) {
2114 			char *val;
2115 			val = db_get_val(ctx, user, realm, "remediation",
2116 					 dmacc);
2117 			if (val && strcmp(val, "policy") == 0)
2118 				db_update_val(ctx, user, realm, "remediation",
2119 					      "", dmacc);
2120 			free(val);
2121 		}
2122 		ret = build_spp_exchange_complete(
2123 			ctx, session_id,
2124 			"Exchange complete, release TLS connection", NULL);
2125 		hs20_eventlog_node(ctx, user, realm, session_id,
2126 				   "Exchange completed", ret);
2127 		db_remove_session(ctx, user, realm, session_id);
2128 		return ret;
2129 	}
2130 
2131 	ret = build_spp_exchange_complete(ctx, session_id, "Error occurred",
2132 					  "Other");
2133 	hs20_eventlog_node(ctx, user, realm, session_id, "Error occurred", ret);
2134 	db_remove_session(ctx, user, realm, session_id);
2135 	xml_node_get_attr_value_free(ctx->xml, status);
2136 	return ret;
2137 }
2138 
2139 
2140 #define SPP_SESSION_ID_LEN 16
2141 
gen_spp_session_id(void)2142 static char * gen_spp_session_id(void)
2143 {
2144 	FILE *f;
2145 	int i;
2146 	char *session;
2147 
2148 	session = os_malloc(SPP_SESSION_ID_LEN * 2 + 1);
2149 	if (session == NULL)
2150 		return NULL;
2151 
2152 	f = fopen("/dev/urandom", "r");
2153 	if (f == NULL) {
2154 		os_free(session);
2155 		return NULL;
2156 	}
2157 	for (i = 0; i < SPP_SESSION_ID_LEN; i++)
2158 		os_snprintf(session + i * 2, 3, "%02x", fgetc(f));
2159 
2160 	fclose(f);
2161 	return session;
2162 }
2163 
hs20_spp_server_process(struct hs20_svc * ctx,xml_node_t * node,const char * auth_user,const char * auth_realm,int dmacc)2164 xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node,
2165 				     const char *auth_user,
2166 				     const char *auth_realm, int dmacc)
2167 {
2168 	xml_node_t *ret = NULL;
2169 	char *session_id;
2170 	const char *op_name;
2171 	char *xml_err;
2172 	char fname[200];
2173 
2174 	debug_dump_node(ctx, "received request", node);
2175 
2176 	if (!dmacc && auth_user && auth_realm) {
2177 		char *real;
2178 		real = db_get_val(ctx, auth_user, auth_realm, "identity", 0);
2179 		if (!real) {
2180 			real = db_get_val(ctx, auth_user, auth_realm,
2181 					  "identity", 1);
2182 			if (real)
2183 				dmacc = 1;
2184 		}
2185 		os_free(real);
2186 	}
2187 
2188 	snprintf(fname, sizeof(fname), "%s/spp/spp.xsd", ctx->root_dir);
2189 	if (xml_validate(ctx->xml, node, fname, &xml_err) < 0) {
2190 		/*
2191 		 * We may not be able to extract the sessionID from invalid
2192 		 * input, but well, we can try.
2193 		 */
2194 		session_id = xml_node_get_attr_value_ns(ctx->xml, node,
2195 							SPP_NS_URI,
2196 							"sessionID");
2197 		debug_print(ctx, 1,
2198 			    "SPP message failed validation, xsd file: %s  xml-error: %s",
2199 			    fname, xml_err);
2200 		hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2201 				   "SPP message failed validation", node);
2202 		hs20_eventlog(ctx, auth_user, auth_realm, session_id,
2203 			      "Validation errors", xml_err);
2204 		os_free(xml_err);
2205 		xml_node_get_attr_value_free(ctx->xml, session_id);
2206 		/* TODO: what to return here? */
2207 		ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2208 					   "SppValidationError");
2209 		return ret;
2210 	}
2211 
2212 	session_id = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
2213 						"sessionID");
2214 	if (session_id) {
2215 		char *tmp;
2216 		debug_print(ctx, 1, "Received sessionID %s", session_id);
2217 		tmp = os_strdup(session_id);
2218 		xml_node_get_attr_value_free(ctx->xml, session_id);
2219 		if (tmp == NULL)
2220 			return NULL;
2221 		session_id = tmp;
2222 	} else {
2223 		session_id = gen_spp_session_id();
2224 		if (session_id == NULL) {
2225 			debug_print(ctx, 1, "Failed to generate sessionID");
2226 			return NULL;
2227 		}
2228 		debug_print(ctx, 1, "Generated sessionID %s", session_id);
2229 	}
2230 
2231 	op_name = xml_node_get_localname(ctx->xml, node);
2232 	if (op_name == NULL) {
2233 		debug_print(ctx, 1, "Could not get op_name");
2234 		return NULL;
2235 	}
2236 
2237 	if (strcmp(op_name, "sppPostDevData") == 0) {
2238 		hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2239 				   "sppPostDevData received and validated",
2240 				   node);
2241 		ret = hs20_spp_post_dev_data(ctx, node, auth_user, auth_realm,
2242 					     session_id, dmacc);
2243 	} else if (strcmp(op_name, "sppUpdateResponse") == 0) {
2244 		hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2245 				   "sppUpdateResponse received and validated",
2246 				   node);
2247 		ret = hs20_spp_update_response(ctx, node, auth_user,
2248 					       auth_realm, session_id, dmacc);
2249 	} else {
2250 		hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2251 				   "Unsupported SPP message received and "
2252 				   "validated", node);
2253 		debug_print(ctx, 1, "Unsupported operation '%s'", op_name);
2254 		/* TODO: what to return here? */
2255 		ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2256 					   "SppUnknownCommandError");
2257 	}
2258 	os_free(session_id);
2259 
2260 	if (ret == NULL) {
2261 		/* TODO: what to return here? */
2262 		ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2263 					   "SppInternalError");
2264 	}
2265 
2266 	return ret;
2267 }
2268 
2269 
hs20_spp_server_init(struct hs20_svc * ctx)2270 int hs20_spp_server_init(struct hs20_svc *ctx)
2271 {
2272 	char fname[200];
2273 	ctx->db = NULL;
2274 	snprintf(fname, sizeof(fname), "%s/AS/DB/eap_user.db", ctx->root_dir);
2275 	if (sqlite3_open(fname, &ctx->db)) {
2276 		printf("Failed to open sqlite database: %s\n",
2277 		       sqlite3_errmsg(ctx->db));
2278 		sqlite3_close(ctx->db);
2279 		return -1;
2280 	}
2281 
2282 	return 0;
2283 }
2284 
2285 
hs20_spp_server_deinit(struct hs20_svc * ctx)2286 void hs20_spp_server_deinit(struct hs20_svc *ctx)
2287 {
2288 	sqlite3_close(ctx->db);
2289 	ctx->db = NULL;
2290 }
2291