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 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 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 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 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 148 static void usage(void) 149 { 150 printf("usage:\n" 151 "hs20_spp_server -r<root directory> [-f<debug log>]\n"); 152 } 153 154 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