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_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
131static 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
154static 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
178static 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
203static 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
241static 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
257static 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
278static 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
292static 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
299static 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
310static 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
335struct get_db_field_data {
336	const char *field;
337	char *value;
338};
339
340
341static 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
358static 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
387static 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
418static 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
452static 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
475static 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
490static 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
513static 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
530static 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
545static 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
567static 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
578static 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
599static 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
631static 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
655static 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
730static 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
739static 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
785static 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
812static 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
833static 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
855static 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
870static 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
929static 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
984static 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
1040static 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
1104static 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
1124static 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
1155static 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
1164static 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
1191static 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
1255static 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
1300static 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
1415static 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
1467static 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
1504static 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
1530static 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
1570static 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);
1829out:
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
1840static 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
1866static 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
1979out:
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
1991static 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
2117static 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
2139xml_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
2243int 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
2259void hs20_spp_server_deinit(struct hs20_svc *ctx)
2260{
2261	sqlite3_close(ctx->db);
2262	ctx->db = NULL;
2263}
2264