1df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt/*
2df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt * Hotspot 2.0 SPP server - standalone version
3df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
4df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt *
5df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt * See README for more details.
7df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt */
8df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
9df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt#include "includes.h"
10df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt#include <time.h>
11df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt#include <sqlite3.h>
12df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
13df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt#include "common.h"
14df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt#include "xml-utils.h"
15df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt#include "spp_server.h"
16df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
17df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
18df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtstatic void write_timestamp(FILE *f)
19df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt{
20df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	time_t t;
21df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	struct tm *tm;
22df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
23df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	time(&t);
24df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	tm = localtime(&t);
25df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
26df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	fprintf(f, "%04u-%02u-%02u %02u:%02u:%02u ",
27df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
28df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		tm->tm_hour, tm->tm_min, tm->tm_sec);
29df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt}
30df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
31df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
32df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtvoid debug_print(struct hs20_svc *ctx, int print, const char *fmt, ...)
33df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt{
34df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	va_list ap;
35df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
36df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (ctx->debug_log == NULL)
37df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		return;
38df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
39df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	write_timestamp(ctx->debug_log);
40df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	va_start(ap, fmt);
41df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	vfprintf(ctx->debug_log, fmt, ap);
42df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	va_end(ap);
43df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
44df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	fprintf(ctx->debug_log, "\n");
45df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt}
46df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
47df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
48df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtvoid debug_dump_node(struct hs20_svc *ctx, const char *title, xml_node_t *node)
49df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt{
50df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	char *str;
51df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
52df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (ctx->debug_log == NULL)
53df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		return;
54df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	str = xml_node_to_str(ctx->xml, node);
55df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (str == NULL)
56df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		return;
57df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
58df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	write_timestamp(ctx->debug_log);
59df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	fprintf(ctx->debug_log, "%s: '%s'\n", title, str);
60df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	os_free(str);
61df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt}
62df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
63df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
64df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtstatic int process(struct hs20_svc *ctx)
65df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt{
66df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	int dmacc = 0;
67df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	xml_node_t *soap, *spp, *resp;
68df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	char *user, *realm, *post, *str;
69df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
70df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	ctx->addr = getenv("HS20ADDR");
71df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (ctx->addr)
72df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		debug_print(ctx, 1, "Connection from %s", ctx->addr);
73df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
74df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	user = getenv("HS20USER");
75df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (user && strlen(user) == 0)
76df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		user = NULL;
77df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	realm = getenv("HS20REALM");
78df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (realm == NULL) {
79df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		debug_print(ctx, 1, "HS20REALM not set");
80df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		return -1;
81df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
82df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	post = getenv("HS20POST");
83df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (post == NULL) {
84df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		debug_print(ctx, 1, "HS20POST not set");
85df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		return -1;
86df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
87df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
88df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	soap = xml_node_from_buf(ctx->xml, post);
89df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (soap == NULL) {
90df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		debug_print(ctx, 1, "Could not parse SOAP data");
91df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		return -1;
92df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
93df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	debug_dump_node(ctx, "Received SOAP message", soap);
94df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	spp = soap_get_body(ctx->xml, soap);
95df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (spp == NULL) {
96df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		debug_print(ctx, 1, "Could not get SPP message");
97df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		xml_node_free(ctx->xml, soap);
98df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		return -1;
99df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
100df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	debug_dump_node(ctx, "Received SPP message", spp);
101df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
102df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	resp = hs20_spp_server_process(ctx, spp, user, realm, dmacc);
103df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	xml_node_free(ctx->xml, soap);
104df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (resp == NULL && user == NULL) {
105df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		debug_print(ctx, 1, "Request HTTP authentication");
106df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		return 2; /* Request authentication */
107df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
108df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (resp == NULL) {
109df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		debug_print(ctx, 1, "No response");
110df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		return -1;
111df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
112df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
113df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	soap = soap_build_envelope(ctx->xml, resp);
114df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (soap == NULL) {
115df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		debug_print(ctx, 1, "SOAP envelope building failed");
116df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		return -1;
117df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
118df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	str = xml_node_to_str(ctx->xml, soap);
119df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	xml_node_free(ctx->xml, soap);
120df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (str == NULL) {
121df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		debug_print(ctx, 1, "Could not get node string");
122df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		return -1;
123df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
124df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	printf("%s", str);
125df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	free(str);
126df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
127df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	return 0;
128df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt}
129df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
130df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
131df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtstatic void usage(void)
132df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt{
133df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	printf("usage:\n"
134df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	       "hs20_spp_server -r<root directory> [-f<debug log>]\n");
135df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt}
136df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
137df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
138df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtint main(int argc, char *argv[])
139df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt{
140df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	struct hs20_svc ctx;
141df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	int ret;
142df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
143df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	os_memset(&ctx, 0, sizeof(ctx));
144df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	for (;;) {
145df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		int c = getopt(argc, argv, "f:r:");
146df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		if (c < 0)
147df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			break;
148df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		switch (c) {
149df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		case 'f':
150df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			if (ctx.debug_log)
151df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt				break;
152df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			ctx.debug_log = fopen(optarg, "a");
153df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			if (ctx.debug_log == NULL) {
154df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt				printf("Could not write to %s\n", optarg);
155df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt				return -1;
156df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			}
157df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			break;
158df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		case 'r':
159df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			ctx.root_dir = optarg;
160df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			break;
161df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		default:
162df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			usage();
163df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			return -1;
164df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		}
165df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
166df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (ctx.root_dir == NULL) {
167df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		usage();
168df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		return -1;
169df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
170df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	ctx.xml = xml_node_init_ctx(&ctx, NULL);
171df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (ctx.xml == NULL)
172df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		return -1;
173df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (hs20_spp_server_init(&ctx) < 0) {
174df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		xml_node_deinit_ctx(ctx.xml);
175df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		return -1;
176df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
177df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
178df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	ret = process(&ctx);
179df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	debug_print(&ctx, 1, "process() --> %d", ret);
180df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
181df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	xml_node_deinit_ctx(ctx.xml);
182df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	hs20_spp_server_deinit(&ctx);
183df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (ctx.debug_log)
184df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		fclose(ctx.debug_log);
185df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
186df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	return ret;
187df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt}
188