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
34enum 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
47static char * db_get_session_val(struct hs20_svc *ctx, const char *user,
48				 const char *realm, const char *session_id,
49				 const char *field);
50static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm,
51				    const char *field);
52static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
53				 const char *realm, int use_dmacc);
54
55
56static 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
86static 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
106static 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
128static 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
153static 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
176static 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
200static 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
225static 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
263static 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
279static 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
300static 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
314static 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
321static 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
332static 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
357struct get_db_field_data {
358	const char *field;
359	char *value;
360};
361
362
363static 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
380static 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
409static 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
440static 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
474static 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
497static 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
512static 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
535static 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
552static 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
567static 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
589static 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
600static 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
621static 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
653static 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
677static 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
752static 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
761static 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
807static 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
834static 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
855static 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
877static 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
892static 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
951static 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
1006static 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
1062static 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
1126static 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
1146static 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
1177static 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
1186static 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
1213static 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
1277static 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
1322static 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
1442static 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
1494static 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
1531static 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
1557static 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
1597static xml_node_t * hs20_spp_post_dev_data(struct hs20_svc *ctx,
1598					   xml_node_t *node,
1599					   const char *user,
1600					   const char *realm,
1601					   const char *session_id,
1602					   int dmacc)
1603{
1604	const char *req_reason;
1605	char *redirect_uri = NULL;
1606	char *req_reason_buf = NULL;
1607	char str[200];
1608	xml_node_t *ret = NULL, *devinfo = NULL, *devdetail = NULL;
1609	xml_node_t *mo;
1610	char *version;
1611	int valid;
1612	char *supp, *pos;
1613	char *err;
1614
1615	version = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
1616					     "sppVersion");
1617	if (version == NULL || strstr(version, "1.0") == NULL) {
1618		ret = build_post_dev_data_response(
1619			ctx, NULL, session_id, "Error occurred",
1620			"SPP version not supported");
1621		hs20_eventlog_node(ctx, user, realm, session_id,
1622				   "Unsupported sppVersion", ret);
1623		xml_node_get_attr_value_free(ctx->xml, version);
1624		return ret;
1625	}
1626	xml_node_get_attr_value_free(ctx->xml, version);
1627
1628	mo = get_node(ctx->xml, node, "supportedMOList");
1629	if (mo == NULL) {
1630		ret = build_post_dev_data_response(
1631			ctx, NULL, session_id, "Error occurred",
1632			"Other");
1633		hs20_eventlog_node(ctx, user, realm, session_id,
1634				   "No supportedMOList element", ret);
1635		return ret;
1636	}
1637	supp = xml_node_get_text(ctx->xml, mo);
1638	for (pos = supp; pos && *pos; pos++)
1639		*pos = tolower(*pos);
1640	if (supp == NULL ||
1641	    strstr(supp, URN_OMA_DM_DEVINFO) == NULL ||
1642	    strstr(supp, URN_OMA_DM_DEVDETAIL) == NULL ||
1643	    strstr(supp, URN_HS20_PPS) == NULL) {
1644		xml_node_get_text_free(ctx->xml, supp);
1645		ret = build_post_dev_data_response(
1646			ctx, NULL, session_id, "Error occurred",
1647			"One or more mandatory MOs not supported");
1648		hs20_eventlog_node(ctx, user, realm, session_id,
1649				   "Unsupported MOs", ret);
1650		return ret;
1651	}
1652	xml_node_get_text_free(ctx->xml, supp);
1653
1654	req_reason_buf = xml_node_get_attr_value(ctx->xml, node,
1655						 "requestReason");
1656	if (req_reason_buf == NULL) {
1657		debug_print(ctx, 1, "No requestReason attribute");
1658		return NULL;
1659	}
1660	req_reason = req_reason_buf;
1661
1662	redirect_uri = xml_node_get_attr_value(ctx->xml, node, "redirectURI");
1663
1664	debug_print(ctx, 1, "requestReason: %s  sessionID: %s  redirectURI: %s",
1665		    req_reason, session_id, redirect_uri);
1666	snprintf(str, sizeof(str), "sppPostDevData: requestReason=%s",
1667		 req_reason);
1668	hs20_eventlog(ctx, user, realm, session_id, str, NULL);
1669
1670	devinfo = spp_get_mo(ctx, node, URN_OMA_DM_DEVINFO, &valid, &err);
1671	if (devinfo == NULL) {
1672		ret = build_post_dev_data_response(ctx, NULL, session_id,
1673						   "Error occurred", "Other");
1674		hs20_eventlog_node(ctx, user, realm, session_id,
1675				   "No DevInfo moContainer in sppPostDevData",
1676				   ret);
1677		os_free(err);
1678		goto out;
1679	}
1680
1681	hs20_eventlog_node(ctx, user, realm, session_id,
1682			   "Received DevInfo MO", devinfo);
1683	if (valid == 0) {
1684		hs20_eventlog(ctx, user, realm, session_id,
1685			      "OMA-DM DDF DTD validation errors in DevInfo MO",
1686			      err);
1687		ret = build_post_dev_data_response(ctx, NULL, session_id,
1688						   "Error occurred", "Other");
1689		os_free(err);
1690		goto out;
1691	}
1692	os_free(err);
1693	if (user)
1694		db_update_mo(ctx, user, realm, "devinfo", devinfo);
1695
1696	devdetail = spp_get_mo(ctx, node, URN_OMA_DM_DEVDETAIL, &valid, &err);
1697	if (devdetail == NULL) {
1698		ret = build_post_dev_data_response(ctx, NULL, session_id,
1699						   "Error occurred", "Other");
1700		hs20_eventlog_node(ctx, user, realm, session_id,
1701				   "No DevDetail moContainer in sppPostDevData",
1702				   ret);
1703		os_free(err);
1704		goto out;
1705	}
1706
1707	hs20_eventlog_node(ctx, user, realm, session_id,
1708			   "Received DevDetail MO", devdetail);
1709	if (valid == 0) {
1710		hs20_eventlog(ctx, user, realm, session_id,
1711			      "OMA-DM DDF DTD validation errors "
1712			      "in DevDetail MO", err);
1713		ret = build_post_dev_data_response(ctx, NULL, session_id,
1714						   "Error occurred", "Other");
1715		os_free(err);
1716		goto out;
1717	}
1718	os_free(err);
1719	if (user)
1720		db_update_mo(ctx, user, realm, "devdetail", devdetail);
1721
1722	if (user)
1723		mo = spp_get_mo(ctx, node, URN_HS20_PPS, &valid, &err);
1724	else {
1725		mo = NULL;
1726		err = NULL;
1727	}
1728	if (user && mo) {
1729		hs20_eventlog_node(ctx, user, realm, session_id,
1730				   "Received PPS MO", mo);
1731		if (valid == 0) {
1732			hs20_eventlog(ctx, user, realm, session_id,
1733				      "OMA-DM DDF DTD validation errors "
1734				      "in PPS MO", err);
1735			xml_node_get_attr_value_free(ctx->xml, redirect_uri);
1736			os_free(err);
1737			return build_post_dev_data_response(
1738				ctx, NULL, session_id,
1739				"Error occurred", "Other");
1740		}
1741		db_update_mo(ctx, user, realm, "pps", mo);
1742		db_update_val(ctx, user, realm, "fetch_pps", "0", dmacc);
1743		xml_node_free(ctx->xml, mo);
1744	}
1745	os_free(err);
1746
1747	if (user && !mo) {
1748		char *fetch;
1749		int fetch_pps;
1750
1751		fetch = db_get_val(ctx, user, realm, "fetch_pps", dmacc);
1752		fetch_pps = fetch ? atoi(fetch) : 0;
1753		free(fetch);
1754
1755		if (fetch_pps) {
1756			enum hs20_session_operation oper;
1757			if (strcasecmp(req_reason, "Subscription remediation")
1758			    == 0)
1759				oper = CONTINUE_SUBSCRIPTION_REMEDIATION;
1760			else if (strcasecmp(req_reason, "Policy update") == 0)
1761				oper = CONTINUE_POLICY_UPDATE;
1762			else
1763				oper = NO_OPERATION;
1764			if (db_add_session(ctx, user, realm, session_id, NULL,
1765					   NULL, oper) < 0)
1766				goto out;
1767
1768			ret = spp_exec_upload_mo(ctx, session_id,
1769						 URN_HS20_PPS);
1770			hs20_eventlog_node(ctx, user, realm, session_id,
1771					   "request PPS MO upload",
1772					   ret);
1773			goto out;
1774		}
1775	}
1776
1777	if (user && strcasecmp(req_reason, "MO upload") == 0) {
1778		char *val = db_get_session_val(ctx, user, realm, session_id,
1779					       "operation");
1780		enum hs20_session_operation oper;
1781		if (!val) {
1782			debug_print(ctx, 1, "No session %s found to continue",
1783				    session_id);
1784			goto out;
1785		}
1786		oper = atoi(val);
1787		free(val);
1788		if (oper == CONTINUE_SUBSCRIPTION_REMEDIATION)
1789			req_reason = "Subscription remediation";
1790		else if (oper == CONTINUE_POLICY_UPDATE)
1791			req_reason = "Policy update";
1792		else {
1793			debug_print(ctx, 1,
1794				    "No pending operation in session %s",
1795				    session_id);
1796			goto out;
1797		}
1798	}
1799
1800	if (strcasecmp(req_reason, "Subscription registration") == 0) {
1801		ret = hs20_subscription_registration(ctx, realm, session_id,
1802						     redirect_uri);
1803		hs20_eventlog_node(ctx, user, realm, session_id,
1804				   "subscription registration response",
1805				   ret);
1806		goto out;
1807	}
1808	if (user && strcasecmp(req_reason, "Subscription remediation") == 0) {
1809		ret = hs20_subscription_remediation(ctx, user, realm,
1810						    session_id, dmacc,
1811						    redirect_uri);
1812		hs20_eventlog_node(ctx, user, realm, session_id,
1813				   "subscription remediation response",
1814				   ret);
1815		goto out;
1816	}
1817	if (user && strcasecmp(req_reason, "Policy update") == 0) {
1818		ret = hs20_policy_update(ctx, user, realm, session_id, dmacc);
1819		hs20_eventlog_node(ctx, user, realm, session_id,
1820				   "policy update response",
1821				   ret);
1822		goto out;
1823	}
1824
1825	if (strcasecmp(req_reason, "User input completed") == 0) {
1826		if (devinfo)
1827			db_add_session_devinfo(ctx, session_id, devinfo);
1828		if (devdetail)
1829			db_add_session_devdetail(ctx, session_id, devdetail);
1830		ret = hs20_user_input_complete(ctx, user, realm, dmacc,
1831					       session_id);
1832		hs20_eventlog_node(ctx, user, realm, session_id,
1833				   "user input completed response", ret);
1834		goto out;
1835	}
1836
1837	if (strcasecmp(req_reason, "Certificate enrollment completed") == 0) {
1838		ret = hs20_cert_enroll_completed(ctx, user, realm, dmacc,
1839						 session_id);
1840		hs20_eventlog_node(ctx, user, realm, session_id,
1841				   "certificate enrollment response", ret);
1842		goto out;
1843	}
1844
1845	if (strcasecmp(req_reason, "Certificate enrollment failed") == 0) {
1846		ret = hs20_cert_enroll_failed(ctx, user, realm, dmacc,
1847					      session_id);
1848		hs20_eventlog_node(ctx, user, realm, session_id,
1849				   "certificate enrollment failed response",
1850				   ret);
1851		goto out;
1852	}
1853
1854	debug_print(ctx, 1, "Unsupported requestReason '%s' user '%s'",
1855		    req_reason, user);
1856out:
1857	xml_node_get_attr_value_free(ctx->xml, req_reason_buf);
1858	xml_node_get_attr_value_free(ctx->xml, redirect_uri);
1859	if (devinfo)
1860		xml_node_free(ctx->xml, devinfo);
1861	if (devdetail)
1862		xml_node_free(ctx->xml, devdetail);
1863	return ret;
1864}
1865
1866
1867static xml_node_t * build_spp_exchange_complete(struct hs20_svc *ctx,
1868						const char *session_id,
1869						const char *status,
1870						const char *error_code)
1871{
1872	xml_namespace_t *ns;
1873	xml_node_t *spp_node, *node;
1874
1875	spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
1876					"sppExchangeComplete");
1877
1878
1879	xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
1880	xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
1881	xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
1882
1883	if (error_code) {
1884		node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
1885		xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
1886				  error_code);
1887	}
1888
1889	return spp_node;
1890}
1891
1892
1893static int add_subscription(struct hs20_svc *ctx, const char *session_id)
1894{
1895	char *user, *realm, *pw, *pw_mm, *pps, *str;
1896	char *sql;
1897	int ret = -1;
1898	char *free_account;
1899	int free_acc;
1900	char *type;
1901	int cert = 0;
1902	char *cert_pem, *fingerprint;
1903
1904	user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
1905	realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
1906	pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
1907	pw_mm = db_get_session_val(ctx, NULL, NULL, session_id,
1908				   "machine_managed");
1909	pps = db_get_session_val(ctx, NULL, NULL, session_id, "pps");
1910	cert_pem = db_get_session_val(ctx, NULL, NULL, session_id, "cert_pem");
1911	fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
1912	type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
1913	if (type && strcmp(type, "cert") == 0)
1914		cert = 1;
1915	free(type);
1916
1917	if (!user || !realm || !pw) {
1918		debug_print(ctx, 1, "Could not find session info from DB for "
1919			    "the new subscription");
1920		goto out;
1921	}
1922
1923	free_account = db_get_osu_config_val(ctx, realm, "free_account");
1924	free_acc = free_account && strcmp(free_account, user) == 0;
1925	free(free_account);
1926
1927	debug_print(ctx, 1,
1928		    "New subscription: user='%s' realm='%s' free_acc=%d",
1929		    user, realm, free_acc);
1930	debug_print(ctx, 1, "New subscription: pps='%s'", pps);
1931
1932	sql = sqlite3_mprintf("UPDATE eventlog SET user=%Q, realm=%Q WHERE "
1933			      "sessionid=%Q AND (user='' OR user IS NULL)",
1934			      user, realm, session_id);
1935	if (sql) {
1936		debug_print(ctx, 1, "DB: %s", sql);
1937		if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
1938			debug_print(ctx, 1, "Failed to update eventlog in "
1939				    "sqlite database: %s",
1940				    sqlite3_errmsg(ctx->db));
1941		}
1942		sqlite3_free(sql);
1943	}
1944
1945	if (free_acc) {
1946		hs20_eventlog(ctx, user, realm, session_id,
1947			      "completed shared free account registration",
1948			      NULL);
1949		ret = 0;
1950		goto out;
1951	}
1952
1953	sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,"
1954			      "methods,cert,cert_pem,machine_managed) VALUES "
1955			      "(%Q,%Q,1,%Q,%Q,%Q,%d)",
1956			      user, realm, cert ? "TLS" : "TTLS-MSCHAPV2",
1957			      fingerprint ? fingerprint : "",
1958			      cert_pem ? cert_pem : "",
1959			      pw_mm && atoi(pw_mm) ? 1 : 0);
1960	if (sql == NULL)
1961		goto out;
1962	debug_print(ctx, 1, "DB: %s", sql);
1963	if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
1964		debug_print(ctx, 1, "Failed to add user in sqlite database: %s",
1965			    sqlite3_errmsg(ctx->db));
1966		sqlite3_free(sql);
1967		goto out;
1968	}
1969	sqlite3_free(sql);
1970
1971	if (cert)
1972		ret = 0;
1973	else
1974		ret = update_password(ctx, user, realm, pw, 0);
1975	if (ret < 0) {
1976		sql = sqlite3_mprintf("DELETE FROM users WHERE identity=%Q AND "
1977				      "realm=%Q AND phase2=1",
1978				      user, realm);
1979		if (sql) {
1980			debug_print(ctx, 1, "DB: %s", sql);
1981			sqlite3_exec(ctx->db, sql, NULL, NULL, NULL);
1982			sqlite3_free(sql);
1983		}
1984	}
1985
1986	if (pps)
1987		db_update_mo_str(ctx, user, realm, "pps", pps);
1988
1989	str = db_get_session_val(ctx, NULL, NULL, session_id, "devinfo");
1990	if (str) {
1991		db_update_mo_str(ctx, user, realm, "devinfo", str);
1992		free(str);
1993	}
1994
1995	str = db_get_session_val(ctx, NULL, NULL, session_id, "devdetail");
1996	if (str) {
1997		db_update_mo_str(ctx, user, realm, "devdetail", str);
1998		free(str);
1999	}
2000
2001	if (ret == 0) {
2002		hs20_eventlog(ctx, user, realm, session_id,
2003			      "completed subscription registration", NULL);
2004	}
2005
2006out:
2007	free(user);
2008	free(realm);
2009	free(pw);
2010	free(pw_mm);
2011	free(pps);
2012	free(cert_pem);
2013	free(fingerprint);
2014	return ret;
2015}
2016
2017
2018static xml_node_t * hs20_spp_update_response(struct hs20_svc *ctx,
2019					     xml_node_t *node,
2020					     const char *user,
2021					     const char *realm,
2022					     const char *session_id,
2023					     int dmacc)
2024{
2025	char *status;
2026	xml_node_t *ret;
2027	char *val;
2028	enum hs20_session_operation oper;
2029
2030	status = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
2031					    "sppStatus");
2032	if (status == NULL) {
2033		debug_print(ctx, 1, "No sppStatus attribute");
2034		return NULL;
2035	}
2036
2037	debug_print(ctx, 1, "sppUpdateResponse: sppStatus: %s  sessionID: %s",
2038		    status, session_id);
2039
2040	val = db_get_session_val(ctx, user, realm, session_id, "operation");
2041	if (!val) {
2042		debug_print(ctx, 1,
2043			    "No session active for user: %s  sessionID: %s",
2044			    user, session_id);
2045		oper = NO_OPERATION;
2046	} else
2047		oper = atoi(val);
2048
2049	if (strcasecmp(status, "OK") == 0) {
2050		char *new_pw = NULL;
2051
2052		xml_node_get_attr_value_free(ctx->xml, status);
2053
2054		if (oper == USER_REMEDIATION) {
2055			new_pw = db_get_session_val(ctx, user, realm,
2056						    session_id, "password");
2057			if (new_pw == NULL || strlen(new_pw) == 0) {
2058				free(new_pw);
2059				ret = build_spp_exchange_complete(
2060					ctx, session_id, "Error occurred",
2061					"Other");
2062				hs20_eventlog_node(ctx, user, realm,
2063						   session_id, "No password "
2064						   "had been assigned for "
2065						   "session", ret);
2066				db_remove_session(ctx, user, realm, session_id);
2067				return ret;
2068			}
2069			oper = UPDATE_PASSWORD;
2070		}
2071		if (oper == UPDATE_PASSWORD) {
2072			if (!new_pw) {
2073				new_pw = db_get_session_val(ctx, user, realm,
2074							    session_id,
2075							    "password");
2076				if (!new_pw) {
2077					db_remove_session(ctx, user, realm,
2078							  session_id);
2079					return NULL;
2080				}
2081			}
2082			debug_print(ctx, 1, "Update user '%s' password in DB",
2083				    user);
2084			if (update_password(ctx, user, realm, new_pw, dmacc) <
2085			    0) {
2086				debug_print(ctx, 1, "Failed to update user "
2087					    "'%s' password in DB", user);
2088				ret = build_spp_exchange_complete(
2089					ctx, session_id, "Error occurred",
2090					"Other");
2091				hs20_eventlog_node(ctx, user, realm,
2092						   session_id, "Failed to "
2093						   "update database", ret);
2094				db_remove_session(ctx, user, realm, session_id);
2095				return ret;
2096			}
2097			hs20_eventlog(ctx, user, realm,
2098				      session_id, "Updated user password "
2099				      "in database", NULL);
2100		}
2101		if (oper == SUBSCRIPTION_REGISTRATION) {
2102			if (add_subscription(ctx, session_id) < 0) {
2103				debug_print(ctx, 1, "Failed to add "
2104					    "subscription into DB");
2105				ret = build_spp_exchange_complete(
2106					ctx, session_id, "Error occurred",
2107					"Other");
2108				hs20_eventlog_node(ctx, user, realm,
2109						   session_id, "Failed to "
2110						   "update database", ret);
2111				db_remove_session(ctx, user, realm, session_id);
2112				return ret;
2113			}
2114		}
2115		if (oper == POLICY_REMEDIATION || oper == POLICY_UPDATE) {
2116			char *val;
2117			val = db_get_val(ctx, user, realm, "remediation",
2118					 dmacc);
2119			if (val && strcmp(val, "policy") == 0)
2120				db_update_val(ctx, user, realm, "remediation",
2121					      "", dmacc);
2122			free(val);
2123		}
2124		ret = build_spp_exchange_complete(
2125			ctx, session_id,
2126			"Exchange complete, release TLS connection", NULL);
2127		hs20_eventlog_node(ctx, user, realm, session_id,
2128				   "Exchange completed", ret);
2129		db_remove_session(ctx, user, realm, session_id);
2130		return ret;
2131	}
2132
2133	ret = build_spp_exchange_complete(ctx, session_id, "Error occurred",
2134					  "Other");
2135	hs20_eventlog_node(ctx, user, realm, session_id, "Error occurred", ret);
2136	db_remove_session(ctx, user, realm, session_id);
2137	xml_node_get_attr_value_free(ctx->xml, status);
2138	return ret;
2139}
2140
2141
2142#define SPP_SESSION_ID_LEN 16
2143
2144static char * gen_spp_session_id(void)
2145{
2146	FILE *f;
2147	int i;
2148	char *session;
2149
2150	session = os_malloc(SPP_SESSION_ID_LEN * 2 + 1);
2151	if (session == NULL)
2152		return NULL;
2153
2154	f = fopen("/dev/urandom", "r");
2155	if (f == NULL) {
2156		os_free(session);
2157		return NULL;
2158	}
2159	for (i = 0; i < SPP_SESSION_ID_LEN; i++)
2160		os_snprintf(session + i * 2, 3, "%02x", fgetc(f));
2161
2162	fclose(f);
2163	return session;
2164}
2165
2166xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node,
2167				     const char *auth_user,
2168				     const char *auth_realm, int dmacc)
2169{
2170	xml_node_t *ret = NULL;
2171	char *session_id;
2172	const char *op_name;
2173	char *xml_err;
2174	char fname[200];
2175
2176	debug_dump_node(ctx, "received request", node);
2177
2178	if (!dmacc && auth_user && auth_realm) {
2179		char *real;
2180		real = db_get_val(ctx, auth_user, auth_realm, "identity", 0);
2181		if (!real) {
2182			real = db_get_val(ctx, auth_user, auth_realm,
2183					  "identity", 1);
2184			if (real)
2185				dmacc = 1;
2186		}
2187		os_free(real);
2188	}
2189
2190	snprintf(fname, sizeof(fname), "%s/spp/spp.xsd", ctx->root_dir);
2191	if (xml_validate(ctx->xml, node, fname, &xml_err) < 0) {
2192		/*
2193		 * We may not be able to extract the sessionID from invalid
2194		 * input, but well, we can try.
2195		 */
2196		session_id = xml_node_get_attr_value_ns(ctx->xml, node,
2197							SPP_NS_URI,
2198							"sessionID");
2199		debug_print(ctx, 1,
2200			    "SPP message failed validation, xsd file: %s  xml-error: %s",
2201			    fname, xml_err);
2202		hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2203				   "SPP message failed validation", node);
2204		hs20_eventlog(ctx, auth_user, auth_realm, session_id,
2205			      "Validation errors", xml_err);
2206		os_free(xml_err);
2207		xml_node_get_attr_value_free(ctx->xml, session_id);
2208		/* TODO: what to return here? */
2209		ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2210					   "SppValidationError");
2211		return ret;
2212	}
2213
2214	session_id = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
2215						"sessionID");
2216	if (session_id) {
2217		char *tmp;
2218		debug_print(ctx, 1, "Received sessionID %s", session_id);
2219		tmp = os_strdup(session_id);
2220		xml_node_get_attr_value_free(ctx->xml, session_id);
2221		if (tmp == NULL)
2222			return NULL;
2223		session_id = tmp;
2224	} else {
2225		session_id = gen_spp_session_id();
2226		if (session_id == NULL) {
2227			debug_print(ctx, 1, "Failed to generate sessionID");
2228			return NULL;
2229		}
2230		debug_print(ctx, 1, "Generated sessionID %s", session_id);
2231	}
2232
2233	op_name = xml_node_get_localname(ctx->xml, node);
2234	if (op_name == NULL) {
2235		debug_print(ctx, 1, "Could not get op_name");
2236		return NULL;
2237	}
2238
2239	if (strcmp(op_name, "sppPostDevData") == 0) {
2240		hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2241				   "sppPostDevData received and validated",
2242				   node);
2243		ret = hs20_spp_post_dev_data(ctx, node, auth_user, auth_realm,
2244					     session_id, dmacc);
2245	} else if (strcmp(op_name, "sppUpdateResponse") == 0) {
2246		hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2247				   "sppUpdateResponse received and validated",
2248				   node);
2249		ret = hs20_spp_update_response(ctx, node, auth_user,
2250					       auth_realm, session_id, dmacc);
2251	} else {
2252		hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2253				   "Unsupported SPP message received and "
2254				   "validated", node);
2255		debug_print(ctx, 1, "Unsupported operation '%s'", op_name);
2256		/* TODO: what to return here? */
2257		ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2258					   "SppUnknownCommandError");
2259	}
2260	os_free(session_id);
2261
2262	if (ret == NULL) {
2263		/* TODO: what to return here? */
2264		ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2265					   "SppInternalError");
2266	}
2267
2268	return ret;
2269}
2270
2271
2272int hs20_spp_server_init(struct hs20_svc *ctx)
2273{
2274	char fname[200];
2275	ctx->db = NULL;
2276	snprintf(fname, sizeof(fname), "%s/AS/DB/eap_user.db", ctx->root_dir);
2277	if (sqlite3_open(fname, &ctx->db)) {
2278		printf("Failed to open sqlite database: %s\n",
2279		       sqlite3_errmsg(ctx->db));
2280		sqlite3_close(ctx->db);
2281		return -1;
2282	}
2283
2284	return 0;
2285}
2286
2287
2288void hs20_spp_server_deinit(struct hs20_svc *ctx)
2289{
2290	sqlite3_close(ctx->db);
2291	ctx->db = NULL;
2292}
2293