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