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