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
34 enum 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 CLEAR_REMEDIATION,
45 CERT_REENROLL,
46 };
47
48
49 static char * db_get_session_val(struct hs20_svc *ctx, const char *user,
50 const char *realm, const char *session_id,
51 const char *field);
52 static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm,
53 const char *field);
54 static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
55 const char *realm, int use_dmacc);
56 static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx,
57 const char *session_id,
58 const char *user,
59 const char *realm,
60 int add_est_user);
61
62
db_add_session(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid,const char * pw,const char * redirect_uri,enum hs20_session_operation operation,const u8 * mac_addr)63 static int db_add_session(struct hs20_svc *ctx,
64 const char *user, const char *realm,
65 const char *sessionid, const char *pw,
66 const char *redirect_uri,
67 enum hs20_session_operation operation,
68 const u8 *mac_addr)
69 {
70 char *sql;
71 int ret = 0;
72 char addr[20];
73
74 if (mac_addr)
75 snprintf(addr, sizeof(addr), MACSTR, MAC2STR(mac_addr));
76 else
77 addr[0] = '\0';
78 sql = sqlite3_mprintf("INSERT INTO sessions(timestamp,id,user,realm,"
79 "operation,password,redirect_uri,mac_addr,test) "
80 "VALUES "
81 "(strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
82 "%Q,%Q,%Q,%d,%Q,%Q,%Q,%Q)",
83 sessionid, user ? user : "", realm ? realm : "",
84 operation, pw ? pw : "",
85 redirect_uri ? redirect_uri : "",
86 addr, ctx->test);
87 if (sql == NULL)
88 return -1;
89 debug_print(ctx, 1, "DB: %s", sql);
90 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
91 debug_print(ctx, 1, "Failed to add session entry into sqlite "
92 "database: %s", sqlite3_errmsg(ctx->db));
93 ret = -1;
94 }
95 sqlite3_free(sql);
96 return ret;
97 }
98
99
db_update_session_password(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid,const char * pw)100 static void db_update_session_password(struct hs20_svc *ctx, const char *user,
101 const char *realm, const char *sessionid,
102 const char *pw)
103 {
104 char *sql;
105
106 sql = sqlite3_mprintf("UPDATE sessions SET password=%Q WHERE id=%Q AND "
107 "user=%Q AND realm=%Q",
108 pw, sessionid, user, realm);
109 if (sql == NULL)
110 return;
111 debug_print(ctx, 1, "DB: %s", sql);
112 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
113 debug_print(ctx, 1, "Failed to update session password: %s",
114 sqlite3_errmsg(ctx->db));
115 }
116 sqlite3_free(sql);
117 }
118
119
db_update_session_machine_managed(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid,const int pw_mm)120 static void db_update_session_machine_managed(struct hs20_svc *ctx,
121 const char *user,
122 const char *realm,
123 const char *sessionid,
124 const int pw_mm)
125 {
126 char *sql;
127
128 sql = sqlite3_mprintf("UPDATE sessions SET machine_managed=%Q WHERE id=%Q AND user=%Q AND realm=%Q",
129 pw_mm ? "1" : "0", sessionid, user, realm);
130 if (sql == NULL)
131 return;
132 debug_print(ctx, 1, "DB: %s", sql);
133 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
134 debug_print(ctx, 1,
135 "Failed to update session machine_managed: %s",
136 sqlite3_errmsg(ctx->db));
137 }
138 sqlite3_free(sql);
139 }
140
141
db_add_session_pps(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid,xml_node_t * node)142 static void db_add_session_pps(struct hs20_svc *ctx, const char *user,
143 const char *realm, const char *sessionid,
144 xml_node_t *node)
145 {
146 char *str;
147 char *sql;
148
149 str = xml_node_to_str(ctx->xml, node);
150 if (str == NULL)
151 return;
152 sql = sqlite3_mprintf("UPDATE sessions SET pps=%Q WHERE id=%Q AND "
153 "user=%Q AND realm=%Q",
154 str, sessionid, user, realm);
155 free(str);
156 if (sql == NULL)
157 return;
158 debug_print(ctx, 1, "DB: %s", sql);
159 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
160 debug_print(ctx, 1, "Failed to add session pps: %s",
161 sqlite3_errmsg(ctx->db));
162 }
163 sqlite3_free(sql);
164 }
165
166
db_add_session_devinfo(struct hs20_svc * ctx,const char * sessionid,xml_node_t * node)167 static void db_add_session_devinfo(struct hs20_svc *ctx, const char *sessionid,
168 xml_node_t *node)
169 {
170 char *str;
171 char *sql;
172
173 str = xml_node_to_str(ctx->xml, node);
174 if (str == NULL)
175 return;
176 sql = sqlite3_mprintf("UPDATE sessions SET devinfo=%Q WHERE id=%Q",
177 str, sessionid);
178 free(str);
179 if (sql == NULL)
180 return;
181 debug_print(ctx, 1, "DB: %s", sql);
182 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
183 debug_print(ctx, 1, "Failed to add session devinfo: %s",
184 sqlite3_errmsg(ctx->db));
185 }
186 sqlite3_free(sql);
187 }
188
189
db_add_session_devdetail(struct hs20_svc * ctx,const char * sessionid,xml_node_t * node)190 static void db_add_session_devdetail(struct hs20_svc *ctx,
191 const char *sessionid,
192 xml_node_t *node)
193 {
194 char *str;
195 char *sql;
196
197 str = xml_node_to_str(ctx->xml, node);
198 if (str == NULL)
199 return;
200 sql = sqlite3_mprintf("UPDATE sessions SET devdetail=%Q WHERE id=%Q",
201 str, sessionid);
202 free(str);
203 if (sql == NULL)
204 return;
205 debug_print(ctx, 1, "DB: %s", sql);
206 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
207 debug_print(ctx, 1, "Failed to add session devdetail: %s",
208 sqlite3_errmsg(ctx->db));
209 }
210 sqlite3_free(sql);
211 }
212
213
db_add_session_dmacc(struct hs20_svc * ctx,const char * sessionid,const char * username,const char * password)214 static void db_add_session_dmacc(struct hs20_svc *ctx, const char *sessionid,
215 const char *username, const char *password)
216 {
217 char *sql;
218
219 sql = sqlite3_mprintf("UPDATE sessions SET osu_user=%Q, osu_password=%Q WHERE id=%Q",
220 username, password, sessionid);
221 if (!sql)
222 return;
223 debug_print(ctx, 1, "DB: %s", sql);
224 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
225 debug_print(ctx, 1, "Failed to add session DMAcc: %s",
226 sqlite3_errmsg(ctx->db));
227 }
228 sqlite3_free(sql);
229 }
230
231
db_add_session_eap_method(struct hs20_svc * ctx,const char * sessionid,const char * method)232 static void db_add_session_eap_method(struct hs20_svc *ctx,
233 const char *sessionid,
234 const char *method)
235 {
236 char *sql;
237
238 sql = sqlite3_mprintf("UPDATE sessions SET eap_method=%Q WHERE id=%Q",
239 method, sessionid);
240 if (!sql)
241 return;
242 debug_print(ctx, 1, "DB: %s", sql);
243 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
244 debug_print(ctx, 1, "Failed to add session EAP method: %s",
245 sqlite3_errmsg(ctx->db));
246 }
247 sqlite3_free(sql);
248 }
249
250
db_add_session_id_hash(struct hs20_svc * ctx,const char * sessionid,const char * id_hash)251 static void db_add_session_id_hash(struct hs20_svc *ctx, const char *sessionid,
252 const char *id_hash)
253 {
254 char *sql;
255
256 sql = sqlite3_mprintf("UPDATE sessions SET mobile_identifier_hash=%Q WHERE id=%Q",
257 id_hash, sessionid);
258 if (!sql)
259 return;
260 debug_print(ctx, 1, "DB: %s", sql);
261 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
262 debug_print(ctx, 1, "Failed to add session ID hash: %s",
263 sqlite3_errmsg(ctx->db));
264 }
265 sqlite3_free(sql);
266 }
267
268
db_remove_session(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid)269 static void db_remove_session(struct hs20_svc *ctx,
270 const char *user, const char *realm,
271 const char *sessionid)
272 {
273 char *sql;
274
275 if (user == NULL || realm == NULL) {
276 sql = sqlite3_mprintf("DELETE FROM sessions WHERE "
277 "id=%Q", sessionid);
278 } else {
279 sql = sqlite3_mprintf("DELETE FROM sessions WHERE "
280 "user=%Q AND realm=%Q AND id=%Q",
281 user, realm, sessionid);
282 }
283 if (sql == NULL)
284 return;
285 debug_print(ctx, 1, "DB: %s", sql);
286 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
287 debug_print(ctx, 1, "Failed to delete session entry from "
288 "sqlite database: %s", sqlite3_errmsg(ctx->db));
289 }
290 sqlite3_free(sql);
291 }
292
293
hs20_eventlog(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid,const char * notes,const char * dump)294 static void hs20_eventlog(struct hs20_svc *ctx,
295 const char *user, const char *realm,
296 const char *sessionid, const char *notes,
297 const char *dump)
298 {
299 char *sql;
300 char *user_buf = NULL, *realm_buf = NULL;
301
302 debug_print(ctx, 1, "eventlog: %s", notes);
303
304 if (user == NULL) {
305 user_buf = db_get_session_val(ctx, NULL, NULL, sessionid,
306 "user");
307 user = user_buf;
308 realm_buf = db_get_session_val(ctx, NULL, NULL, sessionid,
309 "realm");
310 realm = realm_buf;
311 }
312
313 sql = sqlite3_mprintf("INSERT INTO eventlog"
314 "(user,realm,sessionid,timestamp,notes,dump,addr)"
315 " VALUES (%Q,%Q,%Q,"
316 "strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
317 "%Q,%Q,%Q)",
318 user, realm, sessionid, notes,
319 dump ? dump : "", ctx->addr ? ctx->addr : "");
320 free(user_buf);
321 free(realm_buf);
322 if (sql == NULL)
323 return;
324 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
325 debug_print(ctx, 1, "Failed to add eventlog entry into sqlite "
326 "database: %s", sqlite3_errmsg(ctx->db));
327 }
328 sqlite3_free(sql);
329 }
330
331
hs20_eventlog_node(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid,const char * notes,xml_node_t * node)332 static void hs20_eventlog_node(struct hs20_svc *ctx,
333 const char *user, const char *realm,
334 const char *sessionid, const char *notes,
335 xml_node_t *node)
336 {
337 char *str;
338
339 if (node)
340 str = xml_node_to_str(ctx->xml, node);
341 else
342 str = NULL;
343 hs20_eventlog(ctx, user, realm, sessionid, notes, str);
344 free(str);
345 }
346
347
db_update_mo_str(struct hs20_svc * ctx,const char * user,const char * realm,const char * name,const char * str)348 static void db_update_mo_str(struct hs20_svc *ctx, const char *user,
349 const char *realm, const char *name,
350 const char *str)
351 {
352 char *sql;
353 if (user == NULL || realm == NULL || name == NULL)
354 return;
355 sql = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE identity=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
356 name, str, user, realm);
357 if (sql == NULL)
358 return;
359 debug_print(ctx, 1, "DB: %s", sql);
360 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
361 debug_print(ctx, 1, "Failed to update user MO entry in sqlite "
362 "database: %s", sqlite3_errmsg(ctx->db));
363 }
364 sqlite3_free(sql);
365 }
366
367
db_update_mo(struct hs20_svc * ctx,const char * user,const char * realm,const char * name,xml_node_t * mo)368 static void db_update_mo(struct hs20_svc *ctx, const char *user,
369 const char *realm, const char *name, xml_node_t *mo)
370 {
371 char *str;
372
373 str = xml_node_to_str(ctx->xml, mo);
374 if (str == NULL)
375 return;
376
377 db_update_mo_str(ctx, user, realm, name, str);
378 free(str);
379 }
380
381
add_text_node(struct hs20_svc * ctx,xml_node_t * parent,const char * name,const char * value)382 static void add_text_node(struct hs20_svc *ctx, xml_node_t *parent,
383 const char *name, const char *value)
384 {
385 xml_node_create_text(ctx->xml, parent, NULL, name, value ? value : "");
386 }
387
388
add_text_node_conf(struct hs20_svc * ctx,const char * realm,xml_node_t * parent,const char * name,const char * field)389 static void add_text_node_conf(struct hs20_svc *ctx, const char *realm,
390 xml_node_t *parent, const char *name,
391 const char *field)
392 {
393 char *val;
394 val = db_get_osu_config_val(ctx, realm, field);
395 xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : "");
396 os_free(val);
397 }
398
399
add_text_node_conf_corrupt(struct hs20_svc * ctx,const char * realm,xml_node_t * parent,const char * name,const char * field)400 static void add_text_node_conf_corrupt(struct hs20_svc *ctx, const char *realm,
401 xml_node_t *parent, const char *name,
402 const char *field)
403 {
404 char *val;
405
406 val = db_get_osu_config_val(ctx, realm, field);
407 if (val) {
408 size_t len;
409
410 len = os_strlen(val);
411 if (len > 0) {
412 if (val[len - 1] == '0')
413 val[len - 1] = '1';
414 else
415 val[len - 1] = '0';
416 }
417 }
418 xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : "");
419 os_free(val);
420 }
421
422
new_password(char * buf,int buflen)423 static int new_password(char *buf, int buflen)
424 {
425 int i;
426
427 if (buflen < 1)
428 return -1;
429 buf[buflen - 1] = '\0';
430 if (os_get_random((unsigned char *) buf, buflen - 1) < 0)
431 return -1;
432
433 for (i = 0; i < buflen - 1; i++) {
434 unsigned char val = buf[i];
435 val %= 2 * 26 + 10;
436 if (val < 26)
437 buf[i] = 'a' + val;
438 else if (val < 2 * 26)
439 buf[i] = 'A' + val - 26;
440 else
441 buf[i] = '0' + val - 2 * 26;
442 }
443
444 return 0;
445 }
446
447
448 struct get_db_field_data {
449 const char *field;
450 char *value;
451 };
452
453
get_db_field(void * ctx,int argc,char * argv[],char * col[])454 static int get_db_field(void *ctx, int argc, char *argv[], char *col[])
455 {
456 struct get_db_field_data *data = ctx;
457 int i;
458
459 for (i = 0; i < argc; i++) {
460 if (os_strcmp(col[i], data->field) == 0 && argv[i]) {
461 os_free(data->value);
462 data->value = os_strdup(argv[i]);
463 break;
464 }
465 }
466
467 return 0;
468 }
469
470
db_get_val(struct hs20_svc * ctx,const char * user,const char * realm,const char * field,int dmacc)471 static char * db_get_val(struct hs20_svc *ctx, const char *user,
472 const char *realm, const char *field, int dmacc)
473 {
474 char *cmd;
475 struct get_db_field_data data;
476
477 cmd = sqlite3_mprintf("SELECT %s FROM users WHERE %s=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
478 field, dmacc ? "osu_user" : "identity",
479 user, realm);
480 if (cmd == NULL)
481 return NULL;
482 memset(&data, 0, sizeof(data));
483 data.field = field;
484 if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
485 {
486 debug_print(ctx, 1, "Could not find user '%s'", user);
487 sqlite3_free(cmd);
488 return NULL;
489 }
490 sqlite3_free(cmd);
491
492 debug_print(ctx, 1, "DB: user='%s' realm='%s' field='%s' dmacc=%d --> "
493 "value='%s'", user, realm, field, dmacc, data.value);
494
495 return data.value;
496 }
497
498
db_update_val(struct hs20_svc * ctx,const char * user,const char * realm,const char * field,const char * val,int dmacc)499 static int db_update_val(struct hs20_svc *ctx, const char *user,
500 const char *realm, const char *field,
501 const char *val, int dmacc)
502 {
503 char *cmd;
504 int ret;
505
506 cmd = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE %s=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
507 field, val, dmacc ? "osu_user" : "identity", user,
508 realm);
509 if (cmd == NULL)
510 return -1;
511 debug_print(ctx, 1, "DB: %s", cmd);
512 if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
513 debug_print(ctx, 1,
514 "Failed to update user in sqlite database: %s",
515 sqlite3_errmsg(ctx->db));
516 ret = -1;
517 } else {
518 debug_print(ctx, 1,
519 "DB: user='%s' realm='%s' field='%s' set to '%s'",
520 user, realm, field, val);
521 ret = 0;
522 }
523 sqlite3_free(cmd);
524
525 return ret;
526 }
527
528
db_get_session_val(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,const char * field)529 static char * db_get_session_val(struct hs20_svc *ctx, const char *user,
530 const char *realm, const char *session_id,
531 const char *field)
532 {
533 char *cmd;
534 struct get_db_field_data data;
535
536 if (user == NULL || realm == NULL) {
537 cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE "
538 "id=%Q", field, session_id);
539 } else {
540 cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE "
541 "user=%Q AND realm=%Q AND id=%Q",
542 field, user, realm, session_id);
543 }
544 if (cmd == NULL)
545 return NULL;
546 debug_print(ctx, 1, "DB: %s", cmd);
547 memset(&data, 0, sizeof(data));
548 data.field = field;
549 if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
550 {
551 debug_print(ctx, 1, "DB: Could not find session %s: %s",
552 session_id, sqlite3_errmsg(ctx->db));
553 sqlite3_free(cmd);
554 return NULL;
555 }
556 sqlite3_free(cmd);
557
558 debug_print(ctx, 1, "DB: return '%s'", data.value);
559 return data.value;
560 }
561
562
update_password(struct hs20_svc * ctx,const char * user,const char * realm,const char * pw,int dmacc)563 static int update_password(struct hs20_svc *ctx, const char *user,
564 const char *realm, const char *pw, int dmacc)
565 {
566 char *cmd;
567
568 cmd = sqlite3_mprintf("UPDATE users SET password=%Q, "
569 "remediation='' "
570 "WHERE %s=%Q AND phase2=1",
571 pw, dmacc ? "osu_user" : "identity",
572 user);
573 if (cmd == NULL)
574 return -1;
575 debug_print(ctx, 1, "DB: %s", cmd);
576 if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
577 debug_print(ctx, 1, "Failed to update database for user '%s'",
578 user);
579 }
580 sqlite3_free(cmd);
581
582 return 0;
583 }
584
585
clear_remediation(struct hs20_svc * ctx,const char * user,const char * realm,int dmacc)586 static int clear_remediation(struct hs20_svc *ctx, const char *user,
587 const char *realm, int dmacc)
588 {
589 char *cmd;
590
591 cmd = sqlite3_mprintf("UPDATE users SET remediation='' WHERE %s=%Q",
592 dmacc ? "osu_user" : "identity",
593 user);
594 if (cmd == NULL)
595 return -1;
596 debug_print(ctx, 1, "DB: %s", cmd);
597 if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
598 debug_print(ctx, 1, "Failed to update database for user '%s'",
599 user);
600 }
601 sqlite3_free(cmd);
602
603 return 0;
604 }
605
606
add_eap_ttls(struct hs20_svc * ctx,xml_node_t * parent)607 static int add_eap_ttls(struct hs20_svc *ctx, xml_node_t *parent)
608 {
609 xml_node_t *node;
610
611 node = xml_node_create(ctx->xml, parent, NULL, "EAPMethod");
612 if (node == NULL)
613 return -1;
614
615 add_text_node(ctx, node, "EAPType", "21");
616 add_text_node(ctx, node, "InnerMethod", "MS-CHAP-V2");
617
618 return 0;
619 }
620
621
build_username_password(struct hs20_svc * ctx,xml_node_t * parent,const char * user,const char * pw)622 static xml_node_t * build_username_password(struct hs20_svc *ctx,
623 xml_node_t *parent,
624 const char *user, const char *pw)
625 {
626 xml_node_t *node;
627 char *b64;
628 size_t len;
629
630 node = xml_node_create(ctx->xml, parent, NULL, "UsernamePassword");
631 if (node == NULL)
632 return NULL;
633
634 add_text_node(ctx, node, "Username", user);
635
636 b64 = base64_encode(pw, strlen(pw), NULL);
637 if (b64 == NULL)
638 return NULL;
639 len = os_strlen(b64);
640 if (len > 0 && b64[len - 1] == '\n')
641 b64[len - 1] = '\0';
642 add_text_node(ctx, node, "Password", b64);
643 free(b64);
644
645 return node;
646 }
647
648
add_username_password(struct hs20_svc * ctx,xml_node_t * cred,const char * user,const char * pw,int machine_managed)649 static int add_username_password(struct hs20_svc *ctx, xml_node_t *cred,
650 const char *user, const char *pw,
651 int machine_managed)
652 {
653 xml_node_t *node;
654
655 node = build_username_password(ctx, cred, user, pw);
656 if (node == NULL)
657 return -1;
658
659 add_text_node(ctx, node, "MachineManaged",
660 machine_managed ? "TRUE" : "FALSE");
661 add_text_node(ctx, node, "SoftTokenApp", "");
662 add_eap_ttls(ctx, node);
663
664 return 0;
665 }
666
667
add_creation_date(struct hs20_svc * ctx,xml_node_t * cred)668 static void add_creation_date(struct hs20_svc *ctx, xml_node_t *cred)
669 {
670 char str[30];
671 time_t now;
672 struct tm tm;
673
674 time(&now);
675 gmtime_r(&now, &tm);
676 snprintf(str, sizeof(str), "%04u-%02u-%02uT%02u:%02u:%02uZ",
677 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
678 tm.tm_hour, tm.tm_min, tm.tm_sec);
679 xml_node_create_text(ctx->xml, cred, NULL, "CreationDate", str);
680 }
681
682
build_credential_pw(struct hs20_svc * ctx,const char * user,const char * realm,const char * pw,int machine_managed)683 static xml_node_t * build_credential_pw(struct hs20_svc *ctx,
684 const char *user, const char *realm,
685 const char *pw, int machine_managed)
686 {
687 xml_node_t *cred;
688
689 cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential");
690 if (cred == NULL) {
691 debug_print(ctx, 1, "Failed to create Credential node");
692 return NULL;
693 }
694 add_creation_date(ctx, cred);
695 if (add_username_password(ctx, cred, user, pw, machine_managed) < 0) {
696 xml_node_free(ctx->xml, cred);
697 return NULL;
698 }
699 add_text_node(ctx, cred, "Realm", realm);
700
701 return cred;
702 }
703
704
build_credential(struct hs20_svc * ctx,const char * user,const char * realm,char * new_pw,size_t new_pw_len)705 static xml_node_t * build_credential(struct hs20_svc *ctx,
706 const char *user, const char *realm,
707 char *new_pw, size_t new_pw_len)
708 {
709 if (new_password(new_pw, new_pw_len) < 0)
710 return NULL;
711 debug_print(ctx, 1, "Update password to '%s'", new_pw);
712 return build_credential_pw(ctx, user, realm, new_pw, 1);
713 }
714
715
build_credential_cert(struct hs20_svc * ctx,const char * user,const char * realm,const char * cert_fingerprint)716 static xml_node_t * build_credential_cert(struct hs20_svc *ctx,
717 const char *user, const char *realm,
718 const char *cert_fingerprint)
719 {
720 xml_node_t *cred, *cert;
721
722 cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential");
723 if (cred == NULL) {
724 debug_print(ctx, 1, "Failed to create Credential node");
725 return NULL;
726 }
727 add_creation_date(ctx, cred);
728 cert = xml_node_create(ctx->xml, cred, NULL, "DigitalCertificate");
729 add_text_node(ctx, cert, "CertificateType", "x509v3");
730 add_text_node(ctx, cert, "CertSHA256Fingerprint", cert_fingerprint);
731 add_text_node(ctx, cred, "Realm", realm);
732
733 return cred;
734 }
735
736
build_post_dev_data_response(struct hs20_svc * ctx,xml_namespace_t ** ret_ns,const char * session_id,const char * status,const char * error_code)737 static xml_node_t * build_post_dev_data_response(struct hs20_svc *ctx,
738 xml_namespace_t **ret_ns,
739 const char *session_id,
740 const char *status,
741 const char *error_code)
742 {
743 xml_node_t *spp_node = NULL;
744 xml_namespace_t *ns;
745
746 spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
747 "sppPostDevDataResponse");
748 if (spp_node == NULL)
749 return NULL;
750 if (ret_ns)
751 *ret_ns = ns;
752
753 xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
754 xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
755 xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
756
757 if (error_code) {
758 xml_node_t *node;
759 node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
760 if (node)
761 xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
762 error_code);
763 }
764
765 return spp_node;
766 }
767
768
add_update_node(struct hs20_svc * ctx,xml_node_t * spp_node,xml_namespace_t * ns,const char * uri,xml_node_t * upd_node)769 static int add_update_node(struct hs20_svc *ctx, xml_node_t *spp_node,
770 xml_namespace_t *ns, const char *uri,
771 xml_node_t *upd_node)
772 {
773 xml_node_t *node, *tnds;
774 char *str;
775
776 tnds = mo_to_tnds(ctx->xml, upd_node, 0, NULL, NULL);
777 if (!tnds)
778 return -1;
779
780 str = xml_node_to_str(ctx->xml, tnds);
781 xml_node_free(ctx->xml, tnds);
782 if (str == NULL)
783 return -1;
784 node = xml_node_create_text(ctx->xml, spp_node, ns, "updateNode", str);
785 free(str);
786
787 xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", uri);
788
789 return 0;
790 }
791
792
read_subrem_file(struct hs20_svc * ctx,const char * subrem_id,char * uri,size_t uri_size)793 static xml_node_t * read_subrem_file(struct hs20_svc *ctx,
794 const char *subrem_id,
795 char *uri, size_t uri_size)
796 {
797 char fname[200];
798 char *buf, *buf2, *pos;
799 size_t len;
800 xml_node_t *node;
801
802 os_snprintf(fname, sizeof(fname), "%s/spp/subrem/%s",
803 ctx->root_dir, subrem_id);
804 debug_print(ctx, 1, "Use subrem file %s", fname);
805
806 buf = os_readfile(fname, &len);
807 if (!buf)
808 return NULL;
809 buf2 = os_realloc(buf, len + 1);
810 if (!buf2) {
811 os_free(buf);
812 return NULL;
813 }
814 buf = buf2;
815 buf[len] = '\0';
816
817 pos = os_strchr(buf, '\n');
818 if (!pos) {
819 os_free(buf);
820 return NULL;
821 }
822 *pos++ = '\0';
823 os_strlcpy(uri, buf, uri_size);
824
825 node = xml_node_from_buf(ctx->xml, pos);
826 os_free(buf);
827
828 return node;
829 }
830
831
build_sub_rem_resp(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,int machine_rem,int dmacc)832 static xml_node_t * build_sub_rem_resp(struct hs20_svc *ctx,
833 const char *user, const char *realm,
834 const char *session_id,
835 int machine_rem, int dmacc)
836 {
837 xml_namespace_t *ns;
838 xml_node_t *spp_node, *cred;
839 char buf[400];
840 char new_pw[33];
841 char *status;
842 char *cert;
843
844 cert = db_get_val(ctx, user, realm, "cert", dmacc);
845 if (cert && cert[0] == '\0') {
846 os_free(cert);
847 cert = NULL;
848 }
849 if (cert) {
850 char *subrem;
851
852 /* No change needed in PPS MO unless specifically asked to */
853 cred = NULL;
854 buf[0] = '\0';
855
856 subrem = db_get_val(ctx, user, realm, "subrem", dmacc);
857 if (subrem && subrem[0]) {
858 cred = read_subrem_file(ctx, subrem, buf, sizeof(buf));
859 if (!cred) {
860 debug_print(ctx, 1,
861 "Could not create updateNode from subrem file");
862 os_free(subrem);
863 os_free(cert);
864 return NULL;
865 }
866 }
867 os_free(subrem);
868 } else {
869 char *real_user = NULL;
870 char *pw;
871
872 if (dmacc) {
873 real_user = db_get_val(ctx, user, realm, "identity",
874 dmacc);
875 if (!real_user) {
876 debug_print(ctx, 1,
877 "Could not find user identity for dmacc user '%s'",
878 user);
879 return NULL;
880 }
881 }
882
883 pw = db_get_session_val(ctx, user, realm, session_id,
884 "password");
885 if (pw && pw[0]) {
886 debug_print(ctx, 1, "New password from the user: '%s'",
887 pw);
888 snprintf(new_pw, sizeof(new_pw), "%s", pw);
889 free(pw);
890 cred = build_credential_pw(ctx,
891 real_user ? real_user : user,
892 realm, new_pw, 0);
893 } else {
894 cred = build_credential(ctx,
895 real_user ? real_user : user,
896 realm, new_pw, sizeof(new_pw));
897 }
898
899 free(real_user);
900 if (!cred) {
901 debug_print(ctx, 1, "Could not build credential");
902 os_free(cert);
903 return NULL;
904 }
905
906 snprintf(buf, sizeof(buf),
907 "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
908 realm);
909 }
910
911 status = "Remediation complete, request sppUpdateResponse";
912 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
913 NULL);
914 if (spp_node == NULL) {
915 debug_print(ctx, 1, "Could not build sppPostDevDataResponse");
916 os_free(cert);
917 return NULL;
918 }
919
920 if ((cred && add_update_node(ctx, spp_node, ns, buf, cred) < 0) ||
921 (!cred && !xml_node_create(ctx->xml, spp_node, ns, "noMOUpdate"))) {
922 debug_print(ctx, 1, "Could not add update node");
923 xml_node_free(ctx->xml, spp_node);
924 os_free(cert);
925 return NULL;
926 }
927
928 hs20_eventlog_node(ctx, user, realm, session_id,
929 machine_rem ? "machine remediation" :
930 "user remediation", cred);
931 xml_node_free(ctx->xml, cred);
932
933 if (cert) {
934 debug_print(ctx, 1, "Request DB remediation clearing on success notification (certificate credential)");
935 db_add_session(ctx, user, realm, session_id, NULL, NULL,
936 CLEAR_REMEDIATION, NULL);
937 } else {
938 debug_print(ctx, 1, "Request DB password update on success "
939 "notification");
940 db_add_session(ctx, user, realm, session_id, new_pw, NULL,
941 UPDATE_PASSWORD, NULL);
942 }
943 os_free(cert);
944
945 return spp_node;
946 }
947
948
machine_remediation(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,int dmacc)949 static xml_node_t * machine_remediation(struct hs20_svc *ctx,
950 const char *user,
951 const char *realm,
952 const char *session_id, int dmacc)
953 {
954 return build_sub_rem_resp(ctx, user, realm, session_id, 1, dmacc);
955 }
956
957
cert_reenroll(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id)958 static xml_node_t * cert_reenroll(struct hs20_svc *ctx,
959 const char *user,
960 const char *realm,
961 const char *session_id)
962 {
963 db_add_session(ctx, user, realm, session_id, NULL, NULL,
964 CERT_REENROLL, NULL);
965 return spp_exec_get_certificate(ctx, session_id, user, realm, 0);
966 }
967
968
policy_remediation(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,int dmacc)969 static xml_node_t * policy_remediation(struct hs20_svc *ctx,
970 const char *user, const char *realm,
971 const char *session_id, int dmacc)
972 {
973 xml_namespace_t *ns;
974 xml_node_t *spp_node, *policy;
975 char buf[400];
976 const char *status;
977
978 hs20_eventlog(ctx, user, realm, session_id,
979 "requires policy remediation", NULL);
980
981 db_add_session(ctx, user, realm, session_id, NULL, NULL,
982 POLICY_REMEDIATION, NULL);
983
984 policy = build_policy(ctx, user, realm, dmacc);
985 if (!policy) {
986 return build_post_dev_data_response(
987 ctx, NULL, session_id,
988 "No update available at this time", NULL);
989 }
990
991 status = "Remediation complete, request sppUpdateResponse";
992 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
993 NULL);
994 if (spp_node == NULL)
995 return NULL;
996
997 snprintf(buf, sizeof(buf),
998 "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy",
999 realm);
1000
1001 if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
1002 xml_node_free(ctx->xml, spp_node);
1003 xml_node_free(ctx->xml, policy);
1004 return NULL;
1005 }
1006
1007 hs20_eventlog_node(ctx, user, realm, session_id,
1008 "policy update (sub rem)", policy);
1009 xml_node_free(ctx->xml, policy);
1010
1011 return spp_node;
1012 }
1013
1014
browser_remediation(struct hs20_svc * ctx,const char * session_id,const char * redirect_uri,const char * uri)1015 static xml_node_t * browser_remediation(struct hs20_svc *ctx,
1016 const char *session_id,
1017 const char *redirect_uri,
1018 const char *uri)
1019 {
1020 xml_namespace_t *ns;
1021 xml_node_t *spp_node, *exec_node;
1022
1023 if (redirect_uri == NULL) {
1024 debug_print(ctx, 1, "Missing redirectURI attribute for user "
1025 "remediation");
1026 return NULL;
1027 }
1028 debug_print(ctx, 1, "redirectURI %s", redirect_uri);
1029
1030 spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
1031 NULL);
1032 if (spp_node == NULL)
1033 return NULL;
1034
1035 exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
1036 xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI",
1037 uri);
1038 return spp_node;
1039 }
1040
1041
user_remediation(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,const char * redirect_uri)1042 static xml_node_t * user_remediation(struct hs20_svc *ctx, const char *user,
1043 const char *realm, const char *session_id,
1044 const char *redirect_uri)
1045 {
1046 char uri[300], *val;
1047
1048 hs20_eventlog(ctx, user, realm, session_id,
1049 "requires user remediation", NULL);
1050 val = db_get_osu_config_val(ctx, realm, "remediation_url");
1051 if (val == NULL)
1052 return NULL;
1053
1054 db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
1055 USER_REMEDIATION, NULL);
1056
1057 snprintf(uri, sizeof(uri), "%s%s", val, session_id);
1058 os_free(val);
1059 return browser_remediation(ctx, session_id, redirect_uri, uri);
1060 }
1061
1062
free_remediation(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,const char * redirect_uri)1063 static xml_node_t * free_remediation(struct hs20_svc *ctx,
1064 const char *user, const char *realm,
1065 const char *session_id,
1066 const char *redirect_uri)
1067 {
1068 char uri[300], *val;
1069
1070 hs20_eventlog(ctx, user, realm, session_id,
1071 "requires free/public account remediation", NULL);
1072 val = db_get_osu_config_val(ctx, realm, "free_remediation_url");
1073 if (val == NULL)
1074 return NULL;
1075
1076 db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
1077 FREE_REMEDIATION, NULL);
1078
1079 snprintf(uri, sizeof(uri), "%s%s", val, session_id);
1080 os_free(val);
1081 return browser_remediation(ctx, session_id, redirect_uri, uri);
1082 }
1083
1084
no_sub_rem(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id)1085 static xml_node_t * no_sub_rem(struct hs20_svc *ctx,
1086 const char *user, const char *realm,
1087 const char *session_id)
1088 {
1089 const char *status;
1090
1091 hs20_eventlog(ctx, user, realm, session_id,
1092 "no subscription mediation available", NULL);
1093
1094 status = "No update available at this time";
1095 return build_post_dev_data_response(ctx, NULL, session_id, status,
1096 NULL);
1097 }
1098
1099
hs20_subscription_remediation(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,int dmacc,const char * redirect_uri)1100 static xml_node_t * hs20_subscription_remediation(struct hs20_svc *ctx,
1101 const char *user,
1102 const char *realm,
1103 const char *session_id,
1104 int dmacc,
1105 const char *redirect_uri)
1106 {
1107 char *type, *identity;
1108 xml_node_t *ret;
1109 char *free_account;
1110
1111 identity = db_get_val(ctx, user, realm, "identity", dmacc);
1112 if (identity == NULL || strlen(identity) == 0) {
1113 hs20_eventlog(ctx, user, realm, session_id,
1114 "user not found in database for remediation",
1115 NULL);
1116 os_free(identity);
1117 return build_post_dev_data_response(ctx, NULL, session_id,
1118 "Error occurred",
1119 "Not found");
1120 }
1121 os_free(identity);
1122
1123 free_account = db_get_osu_config_val(ctx, realm, "free_account");
1124 if (free_account && strcmp(free_account, user) == 0) {
1125 free(free_account);
1126 return no_sub_rem(ctx, user, realm, session_id);
1127 }
1128 free(free_account);
1129
1130 type = db_get_val(ctx, user, realm, "remediation", dmacc);
1131 if (type && strcmp(type, "free") != 0) {
1132 char *val;
1133 int shared = 0;
1134 val = db_get_val(ctx, user, realm, "shared", dmacc);
1135 if (val)
1136 shared = atoi(val);
1137 free(val);
1138 if (shared) {
1139 free(type);
1140 return no_sub_rem(ctx, user, realm, session_id);
1141 }
1142 }
1143 if (type && strcmp(type, "user") == 0)
1144 ret = user_remediation(ctx, user, realm, session_id,
1145 redirect_uri);
1146 else if (type && strcmp(type, "free") == 0)
1147 ret = free_remediation(ctx, user, realm, session_id,
1148 redirect_uri);
1149 else if (type && strcmp(type, "policy") == 0)
1150 ret = policy_remediation(ctx, user, realm, session_id, dmacc);
1151 else if (type && strcmp(type, "machine") == 0)
1152 ret = machine_remediation(ctx, user, realm, session_id, dmacc);
1153 else if (type && strcmp(type, "reenroll") == 0)
1154 ret = cert_reenroll(ctx, user, realm, session_id);
1155 else
1156 ret = no_sub_rem(ctx, user, realm, session_id);
1157 free(type);
1158
1159 return ret;
1160 }
1161
1162
read_policy_file(struct hs20_svc * ctx,const char * policy_id)1163 static xml_node_t * read_policy_file(struct hs20_svc *ctx,
1164 const char *policy_id)
1165 {
1166 char fname[200];
1167
1168 snprintf(fname, sizeof(fname), "%s/spp/policy/%s.xml",
1169 ctx->root_dir, policy_id);
1170 debug_print(ctx, 1, "Use policy file %s", fname);
1171
1172 return node_from_file(ctx->xml, fname);
1173 }
1174
1175
update_policy_update_uri(struct hs20_svc * ctx,const char * realm,xml_node_t * policy)1176 static void update_policy_update_uri(struct hs20_svc *ctx, const char *realm,
1177 xml_node_t *policy)
1178 {
1179 xml_node_t *node;
1180 char *url;
1181
1182 node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate/URI");
1183 if (!node)
1184 return;
1185
1186 url = db_get_osu_config_val(ctx, realm, "policy_url");
1187 if (!url)
1188 return;
1189 xml_node_set_text(ctx->xml, node, url);
1190 free(url);
1191 }
1192
1193
build_policy(struct hs20_svc * ctx,const char * user,const char * realm,int use_dmacc)1194 static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
1195 const char *realm, int use_dmacc)
1196 {
1197 char *policy_id;
1198 xml_node_t *policy, *node;
1199
1200 policy_id = db_get_val(ctx, user, realm, "policy", use_dmacc);
1201 if (policy_id == NULL || strlen(policy_id) == 0) {
1202 free(policy_id);
1203 policy_id = strdup("default");
1204 if (policy_id == NULL)
1205 return NULL;
1206 }
1207 policy = read_policy_file(ctx, policy_id);
1208 free(policy_id);
1209 if (policy == NULL)
1210 return NULL;
1211
1212 update_policy_update_uri(ctx, realm, policy);
1213
1214 node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate");
1215 if (node && use_dmacc) {
1216 char *pw;
1217 pw = db_get_val(ctx, user, realm, "osu_password", use_dmacc);
1218 if (pw == NULL ||
1219 build_username_password(ctx, node, user, pw) == NULL) {
1220 debug_print(ctx, 1, "Failed to add Policy/PolicyUpdate/"
1221 "UsernamePassword");
1222 free(pw);
1223 xml_node_free(ctx->xml, policy);
1224 return NULL;
1225 }
1226 free(pw);
1227 }
1228
1229 return policy;
1230 }
1231
1232
hs20_policy_update(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,int dmacc)1233 static xml_node_t * hs20_policy_update(struct hs20_svc *ctx,
1234 const char *user, const char *realm,
1235 const char *session_id, int dmacc)
1236 {
1237 xml_namespace_t *ns;
1238 xml_node_t *spp_node;
1239 xml_node_t *policy;
1240 char buf[400];
1241 const char *status;
1242 char *identity;
1243
1244 identity = db_get_val(ctx, user, realm, "identity", dmacc);
1245 if (identity == NULL || strlen(identity) == 0) {
1246 hs20_eventlog(ctx, user, realm, session_id,
1247 "user not found in database for policy update",
1248 NULL);
1249 os_free(identity);
1250 return build_post_dev_data_response(ctx, NULL, session_id,
1251 "Error occurred",
1252 "Not found");
1253 }
1254 os_free(identity);
1255
1256 policy = build_policy(ctx, user, realm, dmacc);
1257 if (!policy) {
1258 return build_post_dev_data_response(
1259 ctx, NULL, session_id,
1260 "No update available at this time", NULL);
1261 }
1262
1263 db_add_session(ctx, user, realm, session_id, NULL, NULL, POLICY_UPDATE,
1264 NULL);
1265
1266 status = "Update complete, request sppUpdateResponse";
1267 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1268 NULL);
1269 if (spp_node == NULL)
1270 return NULL;
1271
1272 snprintf(buf, sizeof(buf),
1273 "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy",
1274 realm);
1275
1276 if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
1277 xml_node_free(ctx->xml, spp_node);
1278 xml_node_free(ctx->xml, policy);
1279 return NULL;
1280 }
1281
1282 hs20_eventlog_node(ctx, user, realm, session_id, "policy update",
1283 policy);
1284 xml_node_free(ctx->xml, policy);
1285
1286 return spp_node;
1287 }
1288
1289
spp_get_mo(struct hs20_svc * ctx,xml_node_t * node,const char * urn,int * valid,char ** ret_err)1290 static xml_node_t * spp_get_mo(struct hs20_svc *ctx, xml_node_t *node,
1291 const char *urn, int *valid, char **ret_err)
1292 {
1293 xml_node_t *child, *tnds, *mo;
1294 const char *name;
1295 char *mo_urn;
1296 char *str;
1297 char fname[200];
1298
1299 *valid = -1;
1300 if (ret_err)
1301 *ret_err = NULL;
1302
1303 xml_node_for_each_child(ctx->xml, child, node) {
1304 xml_node_for_each_check(ctx->xml, child);
1305 name = xml_node_get_localname(ctx->xml, child);
1306 if (strcmp(name, "moContainer") != 0)
1307 continue;
1308 mo_urn = xml_node_get_attr_value_ns(ctx->xml, child, SPP_NS_URI,
1309 "moURN");
1310 if (strcasecmp(urn, mo_urn) == 0) {
1311 xml_node_get_attr_value_free(ctx->xml, mo_urn);
1312 break;
1313 }
1314 xml_node_get_attr_value_free(ctx->xml, mo_urn);
1315 }
1316
1317 if (child == NULL)
1318 return NULL;
1319
1320 debug_print(ctx, 1, "moContainer text for %s", urn);
1321 debug_dump_node(ctx, "moContainer", child);
1322
1323 str = xml_node_get_text(ctx->xml, child);
1324 debug_print(ctx, 1, "moContainer payload: '%s'", str);
1325 tnds = xml_node_from_buf(ctx->xml, str);
1326 xml_node_get_text_free(ctx->xml, str);
1327 if (tnds == NULL) {
1328 debug_print(ctx, 1, "could not parse moContainer text");
1329 return NULL;
1330 }
1331
1332 snprintf(fname, sizeof(fname), "%s/spp/dm_ddf-v1_2.dtd", ctx->root_dir);
1333 if (xml_validate_dtd(ctx->xml, tnds, fname, ret_err) == 0)
1334 *valid = 1;
1335 else if (ret_err && *ret_err &&
1336 os_strcmp(*ret_err, "No declaration for attribute xmlns of element MgmtTree\n") == 0) {
1337 free(*ret_err);
1338 debug_print(ctx, 1, "Ignore OMA-DM DDF DTD validation error for MgmtTree namespace declaration with xmlns attribute");
1339 *ret_err = NULL;
1340 *valid = 1;
1341 } else
1342 *valid = 0;
1343
1344 mo = tnds_to_mo(ctx->xml, tnds);
1345 xml_node_free(ctx->xml, tnds);
1346 if (mo == NULL) {
1347 debug_print(ctx, 1, "invalid moContainer for %s", urn);
1348 }
1349
1350 return mo;
1351 }
1352
1353
spp_exec_upload_mo(struct hs20_svc * ctx,const char * session_id,const char * urn)1354 static xml_node_t * spp_exec_upload_mo(struct hs20_svc *ctx,
1355 const char *session_id, const char *urn)
1356 {
1357 xml_namespace_t *ns;
1358 xml_node_t *spp_node, *node, *exec_node;
1359
1360 spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
1361 NULL);
1362 if (spp_node == NULL)
1363 return NULL;
1364
1365 exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
1366
1367 node = xml_node_create(ctx->xml, exec_node, ns, "uploadMO");
1368 xml_node_add_attr(ctx->xml, node, ns, "moURN", urn);
1369
1370 return spp_node;
1371 }
1372
1373
hs20_subscription_registration(struct hs20_svc * ctx,const char * realm,const char * session_id,const char * redirect_uri,const u8 * mac_addr)1374 static xml_node_t * hs20_subscription_registration(struct hs20_svc *ctx,
1375 const char *realm,
1376 const char *session_id,
1377 const char *redirect_uri,
1378 const u8 *mac_addr)
1379 {
1380 xml_namespace_t *ns;
1381 xml_node_t *spp_node, *exec_node;
1382 char uri[300], *val;
1383
1384 if (db_add_session(ctx, NULL, realm, session_id, NULL, redirect_uri,
1385 SUBSCRIPTION_REGISTRATION, mac_addr) < 0)
1386 return NULL;
1387 val = db_get_osu_config_val(ctx, realm, "signup_url");
1388 if (!val) {
1389 hs20_eventlog(ctx, NULL, realm, session_id,
1390 "signup_url not configured in osu_config", NULL);
1391 return NULL;
1392 }
1393
1394 spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
1395 NULL);
1396 if (spp_node == NULL)
1397 return NULL;
1398
1399 exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
1400
1401 snprintf(uri, sizeof(uri), "%s%s", val, session_id);
1402 os_free(val);
1403 xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI",
1404 uri);
1405 return spp_node;
1406 }
1407
1408
hs20_user_input_remediation(struct hs20_svc * ctx,const char * user,const char * realm,int dmacc,const char * session_id)1409 static xml_node_t * hs20_user_input_remediation(struct hs20_svc *ctx,
1410 const char *user,
1411 const char *realm, int dmacc,
1412 const char *session_id)
1413 {
1414 return build_sub_rem_resp(ctx, user, realm, session_id, 0, dmacc);
1415 }
1416
1417
db_get_osu_config_val(struct hs20_svc * ctx,const char * realm,const char * field)1418 static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm,
1419 const char *field)
1420 {
1421 char *cmd;
1422 struct get_db_field_data data;
1423
1424 cmd = sqlite3_mprintf("SELECT value FROM osu_config WHERE realm=%Q AND "
1425 "field=%Q", realm, field);
1426 if (cmd == NULL)
1427 return NULL;
1428 debug_print(ctx, 1, "DB: %s", cmd);
1429 memset(&data, 0, sizeof(data));
1430 data.field = "value";
1431 if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
1432 {
1433 debug_print(ctx, 1, "DB: Could not find osu_config %s: %s",
1434 realm, sqlite3_errmsg(ctx->db));
1435 sqlite3_free(cmd);
1436 return NULL;
1437 }
1438 sqlite3_free(cmd);
1439
1440 debug_print(ctx, 1, "DB: return '%s'", data.value);
1441 return data.value;
1442 }
1443
1444
build_pps(struct hs20_svc * ctx,const char * user,const char * realm,const char * pw,const char * cert,int machine_managed,const char * test,const char * imsi,const char * dmacc_username,const char * dmacc_password,xml_node_t * policy_node)1445 static xml_node_t * build_pps(struct hs20_svc *ctx,
1446 const char *user, const char *realm,
1447 const char *pw, const char *cert,
1448 int machine_managed, const char *test,
1449 const char *imsi, const char *dmacc_username,
1450 const char *dmacc_password,
1451 xml_node_t *policy_node)
1452 {
1453 xml_node_t *pps, *c, *trust, *aaa, *aaa1, *upd, *homesp, *p;
1454 xml_node_t *cred, *eap, *userpw;
1455
1456 pps = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
1457 "PerProviderSubscription");
1458 if (!pps) {
1459 xml_node_free(ctx->xml, policy_node);
1460 return NULL;
1461 }
1462
1463 add_text_node(ctx, pps, "UpdateIdentifier", "1");
1464
1465 c = xml_node_create(ctx->xml, pps, NULL, "Cred01");
1466
1467 add_text_node(ctx, c, "CredentialPriority", "1");
1468
1469 if (imsi)
1470 goto skip_aaa_trust_root;
1471 aaa = xml_node_create(ctx->xml, c, NULL, "AAAServerTrustRoot");
1472 aaa1 = xml_node_create(ctx->xml, aaa, NULL, "AAA1");
1473 add_text_node_conf(ctx, realm, aaa1, "CertURL",
1474 "aaa_trust_root_cert_url");
1475 if (test && os_strcmp(test, "corrupt_aaa_hash") == 0) {
1476 debug_print(ctx, 1,
1477 "TEST: Corrupt PPS/Cred*/AAAServerTrustRoot/Root*/CertSHA256FingerPrint");
1478 add_text_node_conf_corrupt(ctx, realm, aaa1,
1479 "CertSHA256Fingerprint",
1480 "aaa_trust_root_cert_fingerprint");
1481 } else {
1482 add_text_node_conf(ctx, realm, aaa1, "CertSHA256Fingerprint",
1483 "aaa_trust_root_cert_fingerprint");
1484 }
1485
1486 if (test && os_strcmp(test, "corrupt_polupd_hash") == 0) {
1487 debug_print(ctx, 1,
1488 "TEST: Corrupt PPS/Cred*/Policy/PolicyUpdate/Trustroot/CertSHA256FingerPrint");
1489 p = xml_node_create(ctx->xml, c, NULL, "Policy");
1490 upd = xml_node_create(ctx->xml, p, NULL, "PolicyUpdate");
1491 add_text_node(ctx, upd, "UpdateInterval", "30");
1492 add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated");
1493 add_text_node(ctx, upd, "Restriction", "Unrestricted");
1494 add_text_node_conf(ctx, realm, upd, "URI", "policy_url");
1495 trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
1496 add_text_node_conf(ctx, realm, trust, "CertURL",
1497 "policy_trust_root_cert_url");
1498 add_text_node_conf_corrupt(ctx, realm, trust,
1499 "CertSHA256Fingerprint",
1500 "policy_trust_root_cert_fingerprint");
1501 }
1502 skip_aaa_trust_root:
1503
1504 upd = xml_node_create(ctx->xml, c, NULL, "SubscriptionUpdate");
1505 add_text_node(ctx, upd, "UpdateInterval", "4294967295");
1506 add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated");
1507 add_text_node(ctx, upd, "Restriction", "HomeSP");
1508 add_text_node_conf(ctx, realm, upd, "URI", "spp_http_auth_url");
1509 trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
1510 add_text_node_conf(ctx, realm, trust, "CertURL", "trust_root_cert_url");
1511 if (test && os_strcmp(test, "corrupt_subrem_hash") == 0) {
1512 debug_print(ctx, 1,
1513 "TEST: Corrupt PPS/Cred*/SubscriptionUpdate/Trustroot/CertSHA256FingerPrint");
1514 add_text_node_conf_corrupt(ctx, realm, trust,
1515 "CertSHA256Fingerprint",
1516 "trust_root_cert_fingerprint");
1517 } else {
1518 add_text_node_conf(ctx, realm, trust, "CertSHA256Fingerprint",
1519 "trust_root_cert_fingerprint");
1520 }
1521
1522 if (dmacc_username &&
1523 !build_username_password(ctx, upd, dmacc_username,
1524 dmacc_password)) {
1525 xml_node_free(ctx->xml, pps);
1526 xml_node_free(ctx->xml, policy_node);
1527 return NULL;
1528 }
1529
1530 if (policy_node)
1531 xml_node_add_child(ctx->xml, c, policy_node);
1532
1533 homesp = xml_node_create(ctx->xml, c, NULL, "HomeSP");
1534 add_text_node_conf(ctx, realm, homesp, "FriendlyName", "friendly_name");
1535 add_text_node_conf(ctx, realm, homesp, "FQDN", "fqdn");
1536
1537 xml_node_create(ctx->xml, c, NULL, "SubscriptionParameters");
1538
1539 cred = xml_node_create(ctx->xml, c, NULL, "Credential");
1540 add_creation_date(ctx, cred);
1541 if (imsi) {
1542 xml_node_t *sim;
1543 const char *type = "18"; /* default to EAP-SIM */
1544
1545 sim = xml_node_create(ctx->xml, cred, NULL, "SIM");
1546 add_text_node(ctx, sim, "IMSI", imsi);
1547 if (ctx->eap_method && os_strcmp(ctx->eap_method, "AKA") == 0)
1548 type = "23";
1549 else if (ctx->eap_method &&
1550 os_strcmp(ctx->eap_method, "AKA'") == 0)
1551 type = "50";
1552 add_text_node(ctx, sim, "EAPType", type);
1553 } else if (cert) {
1554 xml_node_t *dc;
1555 dc = xml_node_create(ctx->xml, cred, NULL,
1556 "DigitalCertificate");
1557 add_text_node(ctx, dc, "CertificateType", "x509v3");
1558 add_text_node(ctx, dc, "CertSHA256Fingerprint", cert);
1559 } else {
1560 userpw = build_username_password(ctx, cred, user, pw);
1561 add_text_node(ctx, userpw, "MachineManaged",
1562 machine_managed ? "TRUE" : "FALSE");
1563 eap = xml_node_create(ctx->xml, userpw, NULL, "EAPMethod");
1564 add_text_node(ctx, eap, "EAPType", "21");
1565 add_text_node(ctx, eap, "InnerMethod", "MS-CHAP-V2");
1566 }
1567 add_text_node(ctx, cred, "Realm", realm);
1568
1569 return pps;
1570 }
1571
1572
spp_exec_get_certificate(struct hs20_svc * ctx,const char * session_id,const char * user,const char * realm,int add_est_user)1573 static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx,
1574 const char *session_id,
1575 const char *user,
1576 const char *realm,
1577 int add_est_user)
1578 {
1579 xml_namespace_t *ns;
1580 xml_node_t *spp_node, *enroll, *exec_node;
1581 char *val;
1582 char password[11];
1583 char *b64;
1584
1585 if (add_est_user && new_password(password, sizeof(password)) < 0)
1586 return NULL;
1587
1588 spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
1589 NULL);
1590 if (spp_node == NULL)
1591 return NULL;
1592
1593 exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
1594
1595 enroll = xml_node_create(ctx->xml, exec_node, ns, "getCertificate");
1596 xml_node_add_attr(ctx->xml, enroll, NULL, "enrollmentProtocol", "EST");
1597
1598 val = db_get_osu_config_val(ctx, realm, "est_url");
1599 xml_node_create_text(ctx->xml, enroll, ns, "enrollmentServerURI",
1600 val ? val : "");
1601 os_free(val);
1602
1603 if (!add_est_user)
1604 return spp_node;
1605
1606 xml_node_create_text(ctx->xml, enroll, ns, "estUserID", user);
1607
1608 b64 = base64_encode(password, strlen(password), NULL);
1609 if (b64 == NULL) {
1610 xml_node_free(ctx->xml, spp_node);
1611 return NULL;
1612 }
1613 xml_node_create_text(ctx->xml, enroll, ns, "estPassword", b64);
1614 free(b64);
1615
1616 db_update_session_password(ctx, user, realm, session_id, password);
1617
1618 return spp_node;
1619 }
1620
1621
hs20_user_input_registration(struct hs20_svc * ctx,const char * session_id,int enrollment_done)1622 static xml_node_t * hs20_user_input_registration(struct hs20_svc *ctx,
1623 const char *session_id,
1624 int enrollment_done)
1625 {
1626 xml_namespace_t *ns;
1627 xml_node_t *spp_node, *node = NULL;
1628 xml_node_t *pps, *tnds;
1629 char buf[400];
1630 char *str;
1631 char *user, *realm, *pw, *type, *mm, *test;
1632 const char *status;
1633 int cert = 0;
1634 int machine_managed = 0;
1635 char *fingerprint;
1636
1637 user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
1638 realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
1639 pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
1640
1641 if (!user || !realm || !pw) {
1642 debug_print(ctx, 1, "Could not find session info from DB for "
1643 "the new subscription");
1644 free(user);
1645 free(realm);
1646 free(pw);
1647 return NULL;
1648 }
1649
1650 mm = db_get_session_val(ctx, NULL, NULL, session_id, "machine_managed");
1651 if (mm && atoi(mm))
1652 machine_managed = 1;
1653 free(mm);
1654
1655 type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
1656 if (type && strcmp(type, "cert") == 0)
1657 cert = 1;
1658 free(type);
1659
1660 if (cert && !enrollment_done) {
1661 xml_node_t *ret;
1662 hs20_eventlog(ctx, user, realm, session_id,
1663 "request client certificate enrollment", NULL);
1664 ret = spp_exec_get_certificate(ctx, session_id, user, realm, 1);
1665 free(user);
1666 free(realm);
1667 free(pw);
1668 return ret;
1669 }
1670
1671 if (!cert && strlen(pw) == 0) {
1672 machine_managed = 1;
1673 free(pw);
1674 pw = malloc(11);
1675 if (pw == NULL || new_password(pw, 11) < 0) {
1676 free(user);
1677 free(realm);
1678 free(pw);
1679 return NULL;
1680 }
1681 }
1682
1683 status = "Provisioning complete, request sppUpdateResponse";
1684 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1685 NULL);
1686 if (spp_node == NULL)
1687 return NULL;
1688
1689 fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
1690 test = db_get_session_val(ctx, NULL, NULL, session_id, "test");
1691 if (test)
1692 debug_print(ctx, 1, "TEST: Requested special behavior: %s",
1693 test);
1694 pps = build_pps(ctx, user, realm, pw,
1695 fingerprint ? fingerprint : NULL, machine_managed,
1696 test, NULL, NULL, NULL, NULL);
1697 free(fingerprint);
1698 free(test);
1699 if (!pps) {
1700 xml_node_free(ctx->xml, spp_node);
1701 free(user);
1702 free(realm);
1703 free(pw);
1704 return NULL;
1705 }
1706
1707 debug_print(ctx, 1, "Request DB subscription registration on success "
1708 "notification");
1709 if (machine_managed) {
1710 db_update_session_password(ctx, user, realm, session_id, pw);
1711 db_update_session_machine_managed(ctx, user, realm, session_id,
1712 machine_managed);
1713 }
1714 db_add_session_pps(ctx, user, realm, session_id, pps);
1715
1716 hs20_eventlog_node(ctx, user, realm, session_id,
1717 "new subscription", pps);
1718 free(user);
1719 free(pw);
1720
1721 tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL);
1722 xml_node_free(ctx->xml, pps);
1723 if (!tnds) {
1724 xml_node_free(ctx->xml, spp_node);
1725 free(realm);
1726 return NULL;
1727 }
1728
1729 str = xml_node_to_str(ctx->xml, tnds);
1730 xml_node_free(ctx->xml, tnds);
1731 if (str == NULL) {
1732 xml_node_free(ctx->xml, spp_node);
1733 free(realm);
1734 return NULL;
1735 }
1736
1737 node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str);
1738 free(str);
1739 snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm);
1740 free(realm);
1741 xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf);
1742 xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS);
1743
1744 return spp_node;
1745 }
1746
1747
hs20_user_input_free_remediation(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id)1748 static xml_node_t * hs20_user_input_free_remediation(struct hs20_svc *ctx,
1749 const char *user,
1750 const char *realm,
1751 const char *session_id)
1752 {
1753 xml_namespace_t *ns;
1754 xml_node_t *spp_node;
1755 xml_node_t *cred;
1756 char buf[400];
1757 char *status;
1758 char *free_account, *pw;
1759
1760 free_account = db_get_osu_config_val(ctx, realm, "free_account");
1761 if (free_account == NULL)
1762 return NULL;
1763 pw = db_get_val(ctx, free_account, realm, "password", 0);
1764 if (pw == NULL) {
1765 free(free_account);
1766 return NULL;
1767 }
1768
1769 cred = build_credential_pw(ctx, free_account, realm, pw, 1);
1770 free(free_account);
1771 free(pw);
1772 if (!cred) {
1773 xml_node_free(ctx->xml, cred);
1774 return NULL;
1775 }
1776
1777 status = "Remediation complete, request sppUpdateResponse";
1778 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1779 NULL);
1780 if (spp_node == NULL)
1781 return NULL;
1782
1783 snprintf(buf, sizeof(buf),
1784 "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
1785 realm);
1786
1787 if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
1788 xml_node_free(ctx->xml, spp_node);
1789 return NULL;
1790 }
1791
1792 hs20_eventlog_node(ctx, user, realm, session_id,
1793 "free/public remediation", cred);
1794 xml_node_free(ctx->xml, cred);
1795
1796 return spp_node;
1797 }
1798
1799
hs20_user_input_complete(struct hs20_svc * ctx,const char * user,const char * realm,int dmacc,const char * session_id)1800 static xml_node_t * hs20_user_input_complete(struct hs20_svc *ctx,
1801 const char *user,
1802 const char *realm, int dmacc,
1803 const char *session_id)
1804 {
1805 char *val;
1806 enum hs20_session_operation oper;
1807
1808 val = db_get_session_val(ctx, user, realm, session_id, "operation");
1809 if (val == NULL) {
1810 debug_print(ctx, 1, "No session %s found to continue",
1811 session_id);
1812 return NULL;
1813 }
1814 oper = atoi(val);
1815 free(val);
1816
1817 if (oper == USER_REMEDIATION) {
1818 return hs20_user_input_remediation(ctx, user, realm, dmacc,
1819 session_id);
1820 }
1821
1822 if (oper == FREE_REMEDIATION) {
1823 return hs20_user_input_free_remediation(ctx, user, realm,
1824 session_id);
1825 }
1826
1827 if (oper == SUBSCRIPTION_REGISTRATION) {
1828 return hs20_user_input_registration(ctx, session_id, 0);
1829 }
1830
1831 debug_print(ctx, 1, "User session %s not in state for user input "
1832 "completion", session_id);
1833 return NULL;
1834 }
1835
1836
hs20_cert_reenroll_complete(struct hs20_svc * ctx,const char * session_id)1837 static xml_node_t * hs20_cert_reenroll_complete(struct hs20_svc *ctx,
1838 const char *session_id)
1839 {
1840 char *user, *realm, *cert;
1841 char *status;
1842 xml_namespace_t *ns;
1843 xml_node_t *spp_node, *cred;
1844 char buf[400];
1845
1846 user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
1847 realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
1848 cert = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
1849 if (!user || !realm || !cert) {
1850 debug_print(ctx, 1,
1851 "Could not find session info from DB for certificate reenrollment");
1852 free(user);
1853 free(realm);
1854 free(cert);
1855 return NULL;
1856 }
1857
1858 cred = build_credential_cert(ctx, user, realm, cert);
1859 if (!cred) {
1860 debug_print(ctx, 1, "Could not build credential");
1861 free(user);
1862 free(realm);
1863 free(cert);
1864 return NULL;
1865 }
1866
1867 status = "Remediation complete, request sppUpdateResponse";
1868 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1869 NULL);
1870 if (spp_node == NULL) {
1871 debug_print(ctx, 1, "Could not build sppPostDevDataResponse");
1872 free(user);
1873 free(realm);
1874 free(cert);
1875 xml_node_free(ctx->xml, cred);
1876 return NULL;
1877 }
1878
1879 snprintf(buf, sizeof(buf),
1880 "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
1881 realm);
1882
1883 if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
1884 debug_print(ctx, 1, "Could not add update node");
1885 xml_node_free(ctx->xml, spp_node);
1886 free(user);
1887 free(realm);
1888 free(cert);
1889 return NULL;
1890 }
1891
1892 hs20_eventlog_node(ctx, user, realm, session_id,
1893 "certificate reenrollment", cred);
1894 xml_node_free(ctx->xml, cred);
1895
1896 free(user);
1897 free(realm);
1898 free(cert);
1899 return spp_node;
1900 }
1901
1902
hs20_cert_enroll_completed(struct hs20_svc * ctx,const char * user,const char * realm,int dmacc,const char * session_id)1903 static xml_node_t * hs20_cert_enroll_completed(struct hs20_svc *ctx,
1904 const char *user,
1905 const char *realm, int dmacc,
1906 const char *session_id)
1907 {
1908 char *val;
1909 enum hs20_session_operation oper;
1910
1911 val = db_get_session_val(ctx, NULL, NULL, session_id, "operation");
1912 if (val == NULL) {
1913 debug_print(ctx, 1, "No session %s found to continue",
1914 session_id);
1915 return NULL;
1916 }
1917 oper = atoi(val);
1918 free(val);
1919
1920 if (oper == SUBSCRIPTION_REGISTRATION)
1921 return hs20_user_input_registration(ctx, session_id, 1);
1922 if (oper == CERT_REENROLL)
1923 return hs20_cert_reenroll_complete(ctx, session_id);
1924
1925 debug_print(ctx, 1, "User session %s not in state for certificate "
1926 "enrollment completion", session_id);
1927 return NULL;
1928 }
1929
1930
hs20_cert_enroll_failed(struct hs20_svc * ctx,const char * user,const char * realm,int dmacc,const char * session_id)1931 static xml_node_t * hs20_cert_enroll_failed(struct hs20_svc *ctx,
1932 const char *user,
1933 const char *realm, int dmacc,
1934 const char *session_id)
1935 {
1936 char *val;
1937 enum hs20_session_operation oper;
1938 xml_node_t *spp_node, *node;
1939 char *status;
1940 xml_namespace_t *ns;
1941
1942 val = db_get_session_val(ctx, user, realm, session_id, "operation");
1943 if (val == NULL) {
1944 debug_print(ctx, 1, "No session %s found to continue",
1945 session_id);
1946 return NULL;
1947 }
1948 oper = atoi(val);
1949 free(val);
1950
1951 if (oper != SUBSCRIPTION_REGISTRATION) {
1952 debug_print(ctx, 1, "User session %s not in state for "
1953 "enrollment failure", session_id);
1954 return NULL;
1955 }
1956
1957 status = "Error occurred";
1958 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1959 NULL);
1960 if (spp_node == NULL)
1961 return NULL;
1962 node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
1963 xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
1964 "Credentials cannot be provisioned at this time");
1965 db_remove_session(ctx, user, realm, session_id);
1966
1967 return spp_node;
1968 }
1969
1970
hs20_sim_provisioning(struct hs20_svc * ctx,const char * user,const char * realm,int dmacc,const char * session_id)1971 static xml_node_t * hs20_sim_provisioning(struct hs20_svc *ctx,
1972 const char *user,
1973 const char *realm, int dmacc,
1974 const char *session_id)
1975 {
1976 xml_namespace_t *ns;
1977 xml_node_t *spp_node, *node = NULL;
1978 xml_node_t *pps, *tnds;
1979 char buf[400];
1980 char *str;
1981 const char *status;
1982 char dmacc_username[32];
1983 char dmacc_password[32];
1984 char *policy;
1985 xml_node_t *policy_node = NULL;
1986
1987 if (!ctx->imsi) {
1988 debug_print(ctx, 1, "IMSI not available for SIM provisioning");
1989 return NULL;
1990 }
1991
1992 if (new_password(dmacc_username, sizeof(dmacc_username)) < 0 ||
1993 new_password(dmacc_password, sizeof(dmacc_password)) < 0) {
1994 debug_print(ctx, 1,
1995 "Failed to generate DMAcc username/password");
1996 return NULL;
1997 }
1998
1999 status = "Provisioning complete, request sppUpdateResponse";
2000 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
2001 NULL);
2002 if (!spp_node)
2003 return NULL;
2004
2005 policy = db_get_osu_config_val(ctx, realm, "sim_policy");
2006 if (policy) {
2007 policy_node = read_policy_file(ctx, policy);
2008 os_free(policy);
2009 if (!policy_node) {
2010 xml_node_free(ctx->xml, spp_node);
2011 return NULL;
2012 }
2013 update_policy_update_uri(ctx, realm, policy_node);
2014 node = get_node_uri(ctx->xml, policy_node,
2015 "Policy/PolicyUpdate");
2016 if (node)
2017 build_username_password(ctx, node, dmacc_username,
2018 dmacc_password);
2019 }
2020
2021 pps = build_pps(ctx, NULL, realm, NULL, NULL, 0, NULL, ctx->imsi,
2022 dmacc_username, dmacc_password, policy_node);
2023 if (!pps) {
2024 xml_node_free(ctx->xml, spp_node);
2025 return NULL;
2026 }
2027
2028 debug_print(ctx, 1,
2029 "Request DB subscription registration on success notification");
2030 if (!user || !user[0])
2031 user = ctx->imsi;
2032 db_add_session(ctx, user, realm, session_id, NULL, NULL,
2033 SUBSCRIPTION_REGISTRATION, NULL);
2034 db_add_session_dmacc(ctx, session_id, dmacc_username, dmacc_password);
2035 if (ctx->eap_method)
2036 db_add_session_eap_method(ctx, session_id, ctx->eap_method);
2037 if (ctx->id_hash)
2038 db_add_session_id_hash(ctx, session_id, ctx->id_hash);
2039 db_add_session_pps(ctx, user, realm, session_id, pps);
2040
2041 hs20_eventlog_node(ctx, user, realm, session_id,
2042 "new subscription", pps);
2043
2044 tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL);
2045 xml_node_free(ctx->xml, pps);
2046 if (!tnds) {
2047 xml_node_free(ctx->xml, spp_node);
2048 return NULL;
2049 }
2050
2051 str = xml_node_to_str(ctx->xml, tnds);
2052 xml_node_free(ctx->xml, tnds);
2053 if (!str) {
2054 xml_node_free(ctx->xml, spp_node);
2055 return NULL;
2056 }
2057
2058 node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str);
2059 free(str);
2060 snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm);
2061 xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf);
2062 xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS);
2063
2064 return spp_node;
2065 }
2066
2067
hs20_spp_post_dev_data(struct hs20_svc * ctx,xml_node_t * node,const char * user,const char * realm,const char * session_id,int dmacc)2068 static xml_node_t * hs20_spp_post_dev_data(struct hs20_svc *ctx,
2069 xml_node_t *node,
2070 const char *user,
2071 const char *realm,
2072 const char *session_id,
2073 int dmacc)
2074 {
2075 const char *req_reason;
2076 char *redirect_uri = NULL;
2077 char *req_reason_buf = NULL;
2078 char str[200];
2079 xml_node_t *ret = NULL, *devinfo = NULL, *devdetail = NULL;
2080 xml_node_t *mo, *macaddr;
2081 char *version;
2082 int valid;
2083 char *supp, *pos;
2084 char *err;
2085 u8 wifi_mac_addr[ETH_ALEN];
2086
2087 version = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
2088 "sppVersion");
2089 if (version == NULL || strstr(version, "1.0") == NULL) {
2090 ret = build_post_dev_data_response(
2091 ctx, NULL, session_id, "Error occurred",
2092 "SPP version not supported");
2093 hs20_eventlog_node(ctx, user, realm, session_id,
2094 "Unsupported sppVersion", ret);
2095 xml_node_get_attr_value_free(ctx->xml, version);
2096 return ret;
2097 }
2098 xml_node_get_attr_value_free(ctx->xml, version);
2099
2100 mo = get_node(ctx->xml, node, "supportedMOList");
2101 if (mo == NULL) {
2102 ret = build_post_dev_data_response(
2103 ctx, NULL, session_id, "Error occurred",
2104 "Other");
2105 hs20_eventlog_node(ctx, user, realm, session_id,
2106 "No supportedMOList element", ret);
2107 return ret;
2108 }
2109 supp = xml_node_get_text(ctx->xml, mo);
2110 for (pos = supp; pos && *pos; pos++)
2111 *pos = tolower(*pos);
2112 if (supp == NULL ||
2113 strstr(supp, URN_OMA_DM_DEVINFO) == NULL ||
2114 strstr(supp, URN_OMA_DM_DEVDETAIL) == NULL ||
2115 strstr(supp, URN_HS20_PPS) == NULL) {
2116 xml_node_get_text_free(ctx->xml, supp);
2117 ret = build_post_dev_data_response(
2118 ctx, NULL, session_id, "Error occurred",
2119 "One or more mandatory MOs not supported");
2120 hs20_eventlog_node(ctx, user, realm, session_id,
2121 "Unsupported MOs", ret);
2122 return ret;
2123 }
2124 xml_node_get_text_free(ctx->xml, supp);
2125
2126 req_reason_buf = xml_node_get_attr_value(ctx->xml, node,
2127 "requestReason");
2128 if (req_reason_buf == NULL) {
2129 debug_print(ctx, 1, "No requestReason attribute");
2130 return NULL;
2131 }
2132 req_reason = req_reason_buf;
2133
2134 redirect_uri = xml_node_get_attr_value(ctx->xml, node, "redirectURI");
2135
2136 debug_print(ctx, 1, "requestReason: %s sessionID: %s redirectURI: %s",
2137 req_reason, session_id, redirect_uri);
2138 snprintf(str, sizeof(str), "sppPostDevData: requestReason=%s",
2139 req_reason);
2140 hs20_eventlog(ctx, user, realm, session_id, str, NULL);
2141
2142 devinfo = spp_get_mo(ctx, node, URN_OMA_DM_DEVINFO, &valid, &err);
2143 if (devinfo == NULL) {
2144 ret = build_post_dev_data_response(ctx, NULL, session_id,
2145 "Error occurred", "Other");
2146 hs20_eventlog_node(ctx, user, realm, session_id,
2147 "No DevInfo moContainer in sppPostDevData",
2148 ret);
2149 os_free(err);
2150 goto out;
2151 }
2152
2153 hs20_eventlog_node(ctx, user, realm, session_id,
2154 "Received DevInfo MO", devinfo);
2155 if (valid == 0) {
2156 hs20_eventlog(ctx, user, realm, session_id,
2157 "OMA-DM DDF DTD validation errors in DevInfo MO",
2158 err);
2159 ret = build_post_dev_data_response(ctx, NULL, session_id,
2160 "Error occurred", "Other");
2161 os_free(err);
2162 goto out;
2163 }
2164 os_free(err);
2165 if (user)
2166 db_update_mo(ctx, user, realm, "devinfo", devinfo);
2167
2168 devdetail = spp_get_mo(ctx, node, URN_OMA_DM_DEVDETAIL, &valid, &err);
2169 if (devdetail == NULL) {
2170 ret = build_post_dev_data_response(ctx, NULL, session_id,
2171 "Error occurred", "Other");
2172 hs20_eventlog_node(ctx, user, realm, session_id,
2173 "No DevDetail moContainer in sppPostDevData",
2174 ret);
2175 os_free(err);
2176 goto out;
2177 }
2178
2179 hs20_eventlog_node(ctx, user, realm, session_id,
2180 "Received DevDetail MO", devdetail);
2181 if (valid == 0) {
2182 hs20_eventlog(ctx, user, realm, session_id,
2183 "OMA-DM DDF DTD validation errors "
2184 "in DevDetail MO", err);
2185 ret = build_post_dev_data_response(ctx, NULL, session_id,
2186 "Error occurred", "Other");
2187 os_free(err);
2188 goto out;
2189 }
2190 os_free(err);
2191
2192 os_memset(wifi_mac_addr, 0, ETH_ALEN);
2193 macaddr = get_node(ctx->xml, devdetail,
2194 "Ext/org.wi-fi/Wi-Fi/Wi-FiMACAddress");
2195 if (macaddr) {
2196 char *addr, buf[50];
2197
2198 addr = xml_node_get_text(ctx->xml, macaddr);
2199 if (addr && hwaddr_compact_aton(addr, wifi_mac_addr) == 0) {
2200 snprintf(buf, sizeof(buf), "DevDetail MAC address: "
2201 MACSTR, MAC2STR(wifi_mac_addr));
2202 hs20_eventlog(ctx, user, realm, session_id, buf, NULL);
2203 xml_node_get_text_free(ctx->xml, addr);
2204 } else {
2205 hs20_eventlog(ctx, user, realm, session_id,
2206 "Could not extract MAC address from DevDetail",
2207 NULL);
2208 }
2209 } else {
2210 hs20_eventlog(ctx, user, realm, session_id,
2211 "No MAC address in DevDetail", NULL);
2212 }
2213
2214 if (user)
2215 db_update_mo(ctx, user, realm, "devdetail", devdetail);
2216
2217 if (user)
2218 mo = spp_get_mo(ctx, node, URN_HS20_PPS, &valid, &err);
2219 else {
2220 mo = NULL;
2221 err = NULL;
2222 }
2223 if (user && mo) {
2224 hs20_eventlog_node(ctx, user, realm, session_id,
2225 "Received PPS MO", mo);
2226 if (valid == 0) {
2227 hs20_eventlog(ctx, user, realm, session_id,
2228 "OMA-DM DDF DTD validation errors "
2229 "in PPS MO", err);
2230 xml_node_get_attr_value_free(ctx->xml, redirect_uri);
2231 os_free(err);
2232 return build_post_dev_data_response(
2233 ctx, NULL, session_id,
2234 "Error occurred", "Other");
2235 }
2236 db_update_mo(ctx, user, realm, "pps", mo);
2237 db_update_val(ctx, user, realm, "fetch_pps", "0", dmacc);
2238 xml_node_free(ctx->xml, mo);
2239 }
2240 os_free(err);
2241
2242 if (user && !mo) {
2243 char *fetch;
2244 int fetch_pps;
2245
2246 fetch = db_get_val(ctx, user, realm, "fetch_pps", dmacc);
2247 fetch_pps = fetch ? atoi(fetch) : 0;
2248 free(fetch);
2249
2250 if (fetch_pps) {
2251 enum hs20_session_operation oper;
2252 if (strcasecmp(req_reason, "Subscription remediation")
2253 == 0)
2254 oper = CONTINUE_SUBSCRIPTION_REMEDIATION;
2255 else if (strcasecmp(req_reason, "Policy update") == 0)
2256 oper = CONTINUE_POLICY_UPDATE;
2257 else
2258 oper = NO_OPERATION;
2259 if (db_add_session(ctx, user, realm, session_id, NULL,
2260 NULL, oper, NULL) < 0)
2261 goto out;
2262
2263 ret = spp_exec_upload_mo(ctx, session_id,
2264 URN_HS20_PPS);
2265 hs20_eventlog_node(ctx, user, realm, session_id,
2266 "request PPS MO upload",
2267 ret);
2268 goto out;
2269 }
2270 }
2271
2272 if (user && strcasecmp(req_reason, "MO upload") == 0) {
2273 char *val = db_get_session_val(ctx, user, realm, session_id,
2274 "operation");
2275 enum hs20_session_operation oper;
2276 if (!val) {
2277 debug_print(ctx, 1, "No session %s found to continue",
2278 session_id);
2279 goto out;
2280 }
2281 oper = atoi(val);
2282 free(val);
2283 if (oper == CONTINUE_SUBSCRIPTION_REMEDIATION)
2284 req_reason = "Subscription remediation";
2285 else if (oper == CONTINUE_POLICY_UPDATE)
2286 req_reason = "Policy update";
2287 else {
2288 debug_print(ctx, 1,
2289 "No pending operation in session %s",
2290 session_id);
2291 goto out;
2292 }
2293 }
2294
2295 if (strcasecmp(req_reason, "Subscription registration") == 0) {
2296 ret = hs20_subscription_registration(ctx, realm, session_id,
2297 redirect_uri,
2298 wifi_mac_addr);
2299 hs20_eventlog_node(ctx, user, realm, session_id,
2300 "subscription registration response",
2301 ret);
2302 goto out;
2303 }
2304 if (user && strcasecmp(req_reason, "Subscription remediation") == 0) {
2305 ret = hs20_subscription_remediation(ctx, user, realm,
2306 session_id, dmacc,
2307 redirect_uri);
2308 hs20_eventlog_node(ctx, user, realm, session_id,
2309 "subscription remediation response",
2310 ret);
2311 goto out;
2312 }
2313 if (user && strcasecmp(req_reason, "Policy update") == 0) {
2314 ret = hs20_policy_update(ctx, user, realm, session_id, dmacc);
2315 hs20_eventlog_node(ctx, user, realm, session_id,
2316 "policy update response",
2317 ret);
2318 goto out;
2319 }
2320
2321 if (strcasecmp(req_reason, "User input completed") == 0) {
2322 db_add_session_devinfo(ctx, session_id, devinfo);
2323 db_add_session_devdetail(ctx, session_id, devdetail);
2324 ret = hs20_user_input_complete(ctx, user, realm, dmacc,
2325 session_id);
2326 hs20_eventlog_node(ctx, user, realm, session_id,
2327 "user input completed response", ret);
2328 goto out;
2329 }
2330
2331 if (strcasecmp(req_reason, "Certificate enrollment completed") == 0) {
2332 ret = hs20_cert_enroll_completed(ctx, user, realm, dmacc,
2333 session_id);
2334 hs20_eventlog_node(ctx, user, realm, session_id,
2335 "certificate enrollment response", ret);
2336 goto out;
2337 }
2338
2339 if (strcasecmp(req_reason, "Certificate enrollment failed") == 0) {
2340 ret = hs20_cert_enroll_failed(ctx, user, realm, dmacc,
2341 session_id);
2342 hs20_eventlog_node(ctx, user, realm, session_id,
2343 "certificate enrollment failed response",
2344 ret);
2345 goto out;
2346 }
2347
2348 if (strcasecmp(req_reason, "Subscription provisioning") == 0) {
2349 ret = hs20_sim_provisioning(ctx, user, realm, dmacc,
2350 session_id);
2351 hs20_eventlog_node(ctx, user, realm, session_id,
2352 "subscription provisioning response",
2353 ret);
2354 goto out;
2355 }
2356
2357 debug_print(ctx, 1, "Unsupported requestReason '%s' user '%s'",
2358 req_reason, user);
2359 out:
2360 xml_node_get_attr_value_free(ctx->xml, req_reason_buf);
2361 xml_node_get_attr_value_free(ctx->xml, redirect_uri);
2362 if (devinfo)
2363 xml_node_free(ctx->xml, devinfo);
2364 if (devdetail)
2365 xml_node_free(ctx->xml, devdetail);
2366 return ret;
2367 }
2368
2369
build_spp_exchange_complete(struct hs20_svc * ctx,const char * session_id,const char * status,const char * error_code)2370 static xml_node_t * build_spp_exchange_complete(struct hs20_svc *ctx,
2371 const char *session_id,
2372 const char *status,
2373 const char *error_code)
2374 {
2375 xml_namespace_t *ns;
2376 xml_node_t *spp_node, *node;
2377
2378 spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
2379 "sppExchangeComplete");
2380
2381
2382 xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
2383 xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
2384 xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
2385
2386 if (error_code) {
2387 node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
2388 xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
2389 error_code);
2390 }
2391
2392 return spp_node;
2393 }
2394
2395
add_subscription(struct hs20_svc * ctx,const char * session_id)2396 static int add_subscription(struct hs20_svc *ctx, const char *session_id)
2397 {
2398 char *user, *realm, *pw, *pw_mm, *pps, *str;
2399 char *osu_user, *osu_password, *eap_method;
2400 char *policy = NULL;
2401 char *sql;
2402 int ret = -1;
2403 char *free_account;
2404 int free_acc;
2405 char *type;
2406 int cert = 0;
2407 char *cert_pem, *fingerprint;
2408 const char *method;
2409
2410 user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
2411 realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
2412 pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
2413 pw_mm = db_get_session_val(ctx, NULL, NULL, session_id,
2414 "machine_managed");
2415 pps = db_get_session_val(ctx, NULL, NULL, session_id, "pps");
2416 cert_pem = db_get_session_val(ctx, NULL, NULL, session_id, "cert_pem");
2417 fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
2418 type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
2419 if (type && strcmp(type, "cert") == 0)
2420 cert = 1;
2421 free(type);
2422 osu_user = db_get_session_val(ctx, NULL, NULL, session_id, "osu_user");
2423 osu_password = db_get_session_val(ctx, NULL, NULL, session_id,
2424 "osu_password");
2425 eap_method = db_get_session_val(ctx, NULL, NULL, session_id,
2426 "eap_method");
2427
2428 if (!user || !realm || !pw) {
2429 debug_print(ctx, 1, "Could not find session info from DB for "
2430 "the new subscription");
2431 goto out;
2432 }
2433
2434 free_account = db_get_osu_config_val(ctx, realm, "free_account");
2435 free_acc = free_account && strcmp(free_account, user) == 0;
2436 free(free_account);
2437
2438 policy = db_get_osu_config_val(ctx, realm, "sim_policy");
2439
2440 debug_print(ctx, 1,
2441 "New subscription: user='%s' realm='%s' free_acc=%d",
2442 user, realm, free_acc);
2443 debug_print(ctx, 1, "New subscription: pps='%s'", pps);
2444
2445 sql = sqlite3_mprintf("UPDATE eventlog SET user=%Q, realm=%Q WHERE "
2446 "sessionid=%Q AND (user='' OR user IS NULL)",
2447 user, realm, session_id);
2448 if (sql) {
2449 debug_print(ctx, 1, "DB: %s", sql);
2450 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
2451 debug_print(ctx, 1, "Failed to update eventlog in "
2452 "sqlite database: %s",
2453 sqlite3_errmsg(ctx->db));
2454 }
2455 sqlite3_free(sql);
2456 }
2457
2458 if (free_acc) {
2459 hs20_eventlog(ctx, user, realm, session_id,
2460 "completed shared free account registration",
2461 NULL);
2462 ret = 0;
2463 goto out;
2464 }
2465
2466 str = db_get_session_val(ctx, NULL, NULL, session_id, "mac_addr");
2467
2468 if (eap_method && eap_method[0])
2469 method = eap_method;
2470 else
2471 method = cert ? "TLS" : "TTLS-MSCHAPV2";
2472 sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,methods,cert,cert_pem,machine_managed,mac_addr,osu_user,osu_password,policy) VALUES (%Q,%Q,%d,%Q,%Q,%Q,%d,%Q,%Q,%Q,%Q)",
2473 user, realm, cert ? 0 : 1,
2474 method,
2475 fingerprint ? fingerprint : "",
2476 cert_pem ? cert_pem : "",
2477 pw_mm && atoi(pw_mm) ? 1 : 0,
2478 str ? str : "",
2479 osu_user ? osu_user : "",
2480 osu_password ? osu_password : "",
2481 policy ? policy : "");
2482 free(str);
2483 if (sql == NULL)
2484 goto out;
2485 debug_print(ctx, 1, "DB: %s", sql);
2486 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
2487 debug_print(ctx, 1, "Failed to add user in sqlite database: %s",
2488 sqlite3_errmsg(ctx->db));
2489 sqlite3_free(sql);
2490 goto out;
2491 }
2492 sqlite3_free(sql);
2493
2494 if (cert)
2495 ret = 0;
2496 else
2497 ret = update_password(ctx, user, realm, pw, 0);
2498 if (ret < 0) {
2499 sql = sqlite3_mprintf("DELETE FROM users WHERE identity=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
2500 user, realm);
2501 if (sql) {
2502 debug_print(ctx, 1, "DB: %s", sql);
2503 sqlite3_exec(ctx->db, sql, NULL, NULL, NULL);
2504 sqlite3_free(sql);
2505 }
2506 }
2507
2508 if (pps)
2509 db_update_mo_str(ctx, user, realm, "pps", pps);
2510
2511 str = db_get_session_val(ctx, NULL, NULL, session_id, "devinfo");
2512 if (str) {
2513 db_update_mo_str(ctx, user, realm, "devinfo", str);
2514 free(str);
2515 }
2516
2517 str = db_get_session_val(ctx, NULL, NULL, session_id, "devdetail");
2518 if (str) {
2519 db_update_mo_str(ctx, user, realm, "devdetail", str);
2520 free(str);
2521 }
2522
2523 if (cert && user) {
2524 const char *serialnum;
2525
2526 str = db_get_session_val(ctx, NULL, NULL, session_id,
2527 "mac_addr");
2528
2529 if (os_strncmp(user, "cert-", 5) == 0)
2530 serialnum = user + 5;
2531 else
2532 serialnum = "";
2533 sql = sqlite3_mprintf("INSERT OR REPLACE INTO cert_enroll (mac_addr,user,realm,serialnum) VALUES(%Q,%Q,%Q,%Q)",
2534 str ? str : "", user, realm ? realm : "",
2535 serialnum);
2536 free(str);
2537 if (sql) {
2538 debug_print(ctx, 1, "DB: %s", sql);
2539 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) !=
2540 SQLITE_OK) {
2541 debug_print(ctx, 1,
2542 "Failed to add cert_enroll entry into sqlite database: %s",
2543 sqlite3_errmsg(ctx->db));
2544 }
2545 sqlite3_free(sql);
2546 }
2547 }
2548
2549 str = db_get_session_val(ctx, NULL, NULL, session_id,
2550 "mobile_identifier_hash");
2551 if (str) {
2552 sql = sqlite3_mprintf("DELETE FROM sim_provisioning WHERE mobile_identifier_hash=%Q",
2553 str);
2554 if (sql) {
2555 debug_print(ctx, 1, "DB: %s", sql);
2556 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) !=
2557 SQLITE_OK) {
2558 debug_print(ctx, 1,
2559 "Failed to delete pending sim_provisioning entry: %s",
2560 sqlite3_errmsg(ctx->db));
2561 }
2562 sqlite3_free(sql);
2563 }
2564 os_free(str);
2565 }
2566
2567 if (ret == 0) {
2568 hs20_eventlog(ctx, user, realm, session_id,
2569 "completed subscription registration", NULL);
2570 }
2571
2572 out:
2573 free(user);
2574 free(realm);
2575 free(pw);
2576 free(pw_mm);
2577 free(pps);
2578 free(cert_pem);
2579 free(fingerprint);
2580 free(osu_user);
2581 free(osu_password);
2582 free(eap_method);
2583 os_free(policy);
2584 return ret;
2585 }
2586
2587
hs20_spp_update_response(struct hs20_svc * ctx,xml_node_t * node,const char * user,const char * realm,const char * session_id,int dmacc)2588 static xml_node_t * hs20_spp_update_response(struct hs20_svc *ctx,
2589 xml_node_t *node,
2590 const char *user,
2591 const char *realm,
2592 const char *session_id,
2593 int dmacc)
2594 {
2595 char *status;
2596 xml_node_t *ret;
2597 char *val;
2598 enum hs20_session_operation oper;
2599
2600 status = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
2601 "sppStatus");
2602 if (status == NULL) {
2603 debug_print(ctx, 1, "No sppStatus attribute");
2604 return NULL;
2605 }
2606
2607 debug_print(ctx, 1, "sppUpdateResponse: sppStatus: %s sessionID: %s",
2608 status, session_id);
2609
2610 val = db_get_session_val(ctx, NULL, NULL, session_id, "operation");
2611 if (!val) {
2612 debug_print(ctx, 1,
2613 "No session active for sessionID: %s",
2614 session_id);
2615 oper = NO_OPERATION;
2616 } else
2617 oper = atoi(val);
2618
2619 if (strcasecmp(status, "OK") == 0) {
2620 char *new_pw = NULL;
2621
2622 xml_node_get_attr_value_free(ctx->xml, status);
2623
2624 if (oper == USER_REMEDIATION) {
2625 new_pw = db_get_session_val(ctx, user, realm,
2626 session_id, "password");
2627 if (new_pw == NULL || strlen(new_pw) == 0) {
2628 free(new_pw);
2629 ret = build_spp_exchange_complete(
2630 ctx, session_id, "Error occurred",
2631 "Other");
2632 hs20_eventlog_node(ctx, user, realm,
2633 session_id, "No password "
2634 "had been assigned for "
2635 "session", ret);
2636 db_remove_session(ctx, user, realm, session_id);
2637 return ret;
2638 }
2639 oper = UPDATE_PASSWORD;
2640 }
2641 if (oper == UPDATE_PASSWORD) {
2642 if (!new_pw) {
2643 new_pw = db_get_session_val(ctx, user, realm,
2644 session_id,
2645 "password");
2646 if (!new_pw) {
2647 db_remove_session(ctx, user, realm,
2648 session_id);
2649 return NULL;
2650 }
2651 }
2652 debug_print(ctx, 1, "Update user '%s' password in DB",
2653 user);
2654 if (update_password(ctx, user, realm, new_pw, dmacc) <
2655 0) {
2656 debug_print(ctx, 1, "Failed to update user "
2657 "'%s' password in DB", user);
2658 ret = build_spp_exchange_complete(
2659 ctx, session_id, "Error occurred",
2660 "Other");
2661 hs20_eventlog_node(ctx, user, realm,
2662 session_id, "Failed to "
2663 "update database", ret);
2664 db_remove_session(ctx, user, realm, session_id);
2665 return ret;
2666 }
2667 hs20_eventlog(ctx, user, realm,
2668 session_id, "Updated user password "
2669 "in database", NULL);
2670 }
2671 if (oper == CLEAR_REMEDIATION) {
2672 debug_print(ctx, 1,
2673 "Clear remediation requirement for user '%s' in DB",
2674 user);
2675 if (clear_remediation(ctx, user, realm, dmacc) < 0) {
2676 debug_print(ctx, 1,
2677 "Failed to clear remediation requirement for user '%s' in DB",
2678 user);
2679 ret = build_spp_exchange_complete(
2680 ctx, session_id, "Error occurred",
2681 "Other");
2682 hs20_eventlog_node(ctx, user, realm,
2683 session_id,
2684 "Failed to update database",
2685 ret);
2686 db_remove_session(ctx, user, realm, session_id);
2687 return ret;
2688 }
2689 hs20_eventlog(ctx, user, realm,
2690 session_id,
2691 "Cleared remediation requirement in database",
2692 NULL);
2693 }
2694 if (oper == SUBSCRIPTION_REGISTRATION) {
2695 if (add_subscription(ctx, session_id) < 0) {
2696 debug_print(ctx, 1, "Failed to add "
2697 "subscription into DB");
2698 ret = build_spp_exchange_complete(
2699 ctx, session_id, "Error occurred",
2700 "Other");
2701 hs20_eventlog_node(ctx, user, realm,
2702 session_id, "Failed to "
2703 "update database", ret);
2704 db_remove_session(ctx, user, realm, session_id);
2705 return ret;
2706 }
2707 }
2708 if (oper == POLICY_REMEDIATION || oper == POLICY_UPDATE) {
2709 char *val;
2710 val = db_get_val(ctx, user, realm, "remediation",
2711 dmacc);
2712 if (val && strcmp(val, "policy") == 0)
2713 db_update_val(ctx, user, realm, "remediation",
2714 "", dmacc);
2715 free(val);
2716 }
2717 if (oper == POLICY_UPDATE)
2718 db_update_val(ctx, user, realm, "polupd_done", "1",
2719 dmacc);
2720 if (oper == CERT_REENROLL) {
2721 char *new_user;
2722 char event[200];
2723
2724 new_user = db_get_session_val(ctx, NULL, NULL,
2725 session_id, "user");
2726 if (!new_user) {
2727 debug_print(ctx, 1,
2728 "Failed to find new user name (cert-serialnum)");
2729 ret = build_spp_exchange_complete(
2730 ctx, session_id, "Error occurred",
2731 "Other");
2732 hs20_eventlog_node(ctx, user, realm,
2733 session_id,
2734 "Failed to find new user name (cert reenroll)",
2735 ret);
2736 db_remove_session(ctx, NULL, NULL, session_id);
2737 return ret;
2738 }
2739
2740 debug_print(ctx, 1,
2741 "Update certificate user entry to use the new serial number (old=%s new=%s)",
2742 user, new_user);
2743 os_snprintf(event, sizeof(event), "renamed user to: %s",
2744 new_user);
2745 hs20_eventlog(ctx, user, realm, session_id, event,
2746 NULL);
2747
2748 if (db_update_val(ctx, user, realm, "identity",
2749 new_user, 0) < 0 ||
2750 db_update_val(ctx, new_user, realm, "remediation",
2751 "", 0) < 0) {
2752 debug_print(ctx, 1,
2753 "Failed to update user name (cert-serialnum)");
2754 ret = build_spp_exchange_complete(
2755 ctx, session_id, "Error occurred",
2756 "Other");
2757 hs20_eventlog_node(ctx, user, realm,
2758 session_id,
2759 "Failed to update user name (cert reenroll)",
2760 ret);
2761 db_remove_session(ctx, NULL, NULL, session_id);
2762 os_free(new_user);
2763 return ret;
2764 }
2765
2766 os_free(new_user);
2767 }
2768 ret = build_spp_exchange_complete(
2769 ctx, session_id,
2770 "Exchange complete, release TLS connection", NULL);
2771 hs20_eventlog_node(ctx, user, realm, session_id,
2772 "Exchange completed", ret);
2773 db_remove_session(ctx, NULL, NULL, session_id);
2774 return ret;
2775 }
2776
2777 ret = build_spp_exchange_complete(ctx, session_id, "Error occurred",
2778 "Other");
2779 hs20_eventlog_node(ctx, user, realm, session_id, "Error occurred", ret);
2780 db_remove_session(ctx, user, realm, session_id);
2781 xml_node_get_attr_value_free(ctx->xml, status);
2782 return ret;
2783 }
2784
2785
2786 #define SPP_SESSION_ID_LEN 16
2787
gen_spp_session_id(void)2788 static char * gen_spp_session_id(void)
2789 {
2790 FILE *f;
2791 int i;
2792 char *session;
2793
2794 session = os_malloc(SPP_SESSION_ID_LEN * 2 + 1);
2795 if (session == NULL)
2796 return NULL;
2797
2798 f = fopen("/dev/urandom", "r");
2799 if (f == NULL) {
2800 os_free(session);
2801 return NULL;
2802 }
2803 for (i = 0; i < SPP_SESSION_ID_LEN; i++)
2804 os_snprintf(session + i * 2, 3, "%02x", fgetc(f));
2805
2806 fclose(f);
2807 return session;
2808 }
2809
hs20_spp_server_process(struct hs20_svc * ctx,xml_node_t * node,const char * auth_user,const char * auth_realm,int dmacc)2810 xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node,
2811 const char *auth_user,
2812 const char *auth_realm, int dmacc)
2813 {
2814 xml_node_t *ret = NULL;
2815 char *session_id;
2816 const char *op_name;
2817 char *xml_err;
2818 char fname[200];
2819
2820 debug_dump_node(ctx, "received request", node);
2821
2822 if (!dmacc && auth_user && auth_realm) {
2823 char *real;
2824 real = db_get_val(ctx, auth_user, auth_realm, "identity", 0);
2825 if (!real) {
2826 real = db_get_val(ctx, auth_user, auth_realm,
2827 "identity", 1);
2828 if (real)
2829 dmacc = 1;
2830 }
2831 os_free(real);
2832 }
2833
2834 snprintf(fname, sizeof(fname), "%s/spp/spp.xsd", ctx->root_dir);
2835 if (xml_validate(ctx->xml, node, fname, &xml_err) < 0) {
2836 /*
2837 * We may not be able to extract the sessionID from invalid
2838 * input, but well, we can try.
2839 */
2840 session_id = xml_node_get_attr_value_ns(ctx->xml, node,
2841 SPP_NS_URI,
2842 "sessionID");
2843 debug_print(ctx, 1,
2844 "SPP message failed validation, xsd file: %s xml-error: %s",
2845 fname, xml_err);
2846 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2847 "SPP message failed validation", node);
2848 hs20_eventlog(ctx, auth_user, auth_realm, session_id,
2849 "Validation errors", xml_err);
2850 os_free(xml_err);
2851 xml_node_get_attr_value_free(ctx->xml, session_id);
2852 /* TODO: what to return here? */
2853 ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2854 "SppValidationError");
2855 return ret;
2856 }
2857
2858 session_id = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
2859 "sessionID");
2860 if (session_id) {
2861 char *tmp;
2862 debug_print(ctx, 1, "Received sessionID %s", session_id);
2863 tmp = os_strdup(session_id);
2864 xml_node_get_attr_value_free(ctx->xml, session_id);
2865 if (tmp == NULL)
2866 return NULL;
2867 session_id = tmp;
2868 } else {
2869 session_id = gen_spp_session_id();
2870 if (session_id == NULL) {
2871 debug_print(ctx, 1, "Failed to generate sessionID");
2872 return NULL;
2873 }
2874 debug_print(ctx, 1, "Generated sessionID %s", session_id);
2875 }
2876
2877 op_name = xml_node_get_localname(ctx->xml, node);
2878 if (op_name == NULL) {
2879 debug_print(ctx, 1, "Could not get op_name");
2880 return NULL;
2881 }
2882
2883 if (strcmp(op_name, "sppPostDevData") == 0) {
2884 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2885 "sppPostDevData received and validated",
2886 node);
2887 ret = hs20_spp_post_dev_data(ctx, node, auth_user, auth_realm,
2888 session_id, dmacc);
2889 } else if (strcmp(op_name, "sppUpdateResponse") == 0) {
2890 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2891 "sppUpdateResponse received and validated",
2892 node);
2893 ret = hs20_spp_update_response(ctx, node, auth_user,
2894 auth_realm, session_id, dmacc);
2895 } else {
2896 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2897 "Unsupported SPP message received and "
2898 "validated", node);
2899 debug_print(ctx, 1, "Unsupported operation '%s'", op_name);
2900 /* TODO: what to return here? */
2901 ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2902 "SppUnknownCommandError");
2903 }
2904 os_free(session_id);
2905
2906 if (ret == NULL) {
2907 /* TODO: what to return here? */
2908 ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2909 "SppInternalError");
2910 }
2911
2912 return ret;
2913 }
2914
2915
hs20_spp_server_init(struct hs20_svc * ctx)2916 int hs20_spp_server_init(struct hs20_svc *ctx)
2917 {
2918 char fname[200];
2919 ctx->db = NULL;
2920 snprintf(fname, sizeof(fname), "%s/AS/DB/eap_user.db", ctx->root_dir);
2921 if (sqlite3_open(fname, &ctx->db)) {
2922 printf("Failed to open sqlite database: %s\n",
2923 sqlite3_errmsg(ctx->db));
2924 sqlite3_close(ctx->db);
2925 return -1;
2926 }
2927
2928 return 0;
2929 }
2930
2931
hs20_spp_server_deinit(struct hs20_svc * ctx)2932 void hs20_spp_server_deinit(struct hs20_svc *ctx)
2933 {
2934 sqlite3_close(ctx->db);
2935 ctx->db = NULL;
2936 }
2937