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 };
45
46
47 static char * db_get_session_val(struct hs20_svc *ctx, const char *user,
48 const char *realm, const char *session_id,
49 const char *field);
50 static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm,
51 const char *field);
52 static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
53 const char *realm, int use_dmacc);
54
55
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)56 static int db_add_session(struct hs20_svc *ctx,
57 const char *user, const char *realm,
58 const char *sessionid, const char *pw,
59 const char *redirect_uri,
60 enum hs20_session_operation operation)
61 {
62 char *sql;
63 int ret = 0;
64
65 sql = sqlite3_mprintf("INSERT INTO sessions(timestamp,id,user,realm,"
66 "operation,password,redirect_uri) "
67 "VALUES "
68 "(strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
69 "%Q,%Q,%Q,%d,%Q,%Q)",
70 sessionid, user ? user : "", realm ? realm : "",
71 operation, pw ? pw : "",
72 redirect_uri ? redirect_uri : "");
73 if (sql == NULL)
74 return -1;
75 debug_print(ctx, 1, "DB: %s", sql);
76 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
77 debug_print(ctx, 1, "Failed to add session entry into sqlite "
78 "database: %s", sqlite3_errmsg(ctx->db));
79 ret = -1;
80 }
81 sqlite3_free(sql);
82 return ret;
83 }
84
85
db_update_session_password(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid,const char * pw)86 static void db_update_session_password(struct hs20_svc *ctx, const char *user,
87 const char *realm, const char *sessionid,
88 const char *pw)
89 {
90 char *sql;
91
92 sql = sqlite3_mprintf("UPDATE sessions SET password=%Q WHERE id=%Q AND "
93 "user=%Q AND realm=%Q",
94 pw, sessionid, user, realm);
95 if (sql == NULL)
96 return;
97 debug_print(ctx, 1, "DB: %s", sql);
98 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
99 debug_print(ctx, 1, "Failed to update session password: %s",
100 sqlite3_errmsg(ctx->db));
101 }
102 sqlite3_free(sql);
103 }
104
105
db_update_session_machine_managed(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid,const int pw_mm)106 static void db_update_session_machine_managed(struct hs20_svc *ctx,
107 const char *user,
108 const char *realm,
109 const char *sessionid,
110 const int pw_mm)
111 {
112 char *sql;
113
114 sql = sqlite3_mprintf("UPDATE sessions SET machine_managed=%Q WHERE id=%Q AND user=%Q AND realm=%Q",
115 pw_mm ? "1" : "0", sessionid, user, realm);
116 if (sql == NULL)
117 return;
118 debug_print(ctx, 1, "DB: %s", sql);
119 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
120 debug_print(ctx, 1,
121 "Failed to update session machine_managed: %s",
122 sqlite3_errmsg(ctx->db));
123 }
124 sqlite3_free(sql);
125 }
126
127
db_add_session_pps(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid,xml_node_t * node)128 static void db_add_session_pps(struct hs20_svc *ctx, const char *user,
129 const char *realm, const char *sessionid,
130 xml_node_t *node)
131 {
132 char *str;
133 char *sql;
134
135 str = xml_node_to_str(ctx->xml, node);
136 if (str == NULL)
137 return;
138 sql = sqlite3_mprintf("UPDATE sessions SET pps=%Q WHERE id=%Q AND "
139 "user=%Q AND realm=%Q",
140 str, sessionid, user, realm);
141 free(str);
142 if (sql == NULL)
143 return;
144 debug_print(ctx, 1, "DB: %s", sql);
145 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
146 debug_print(ctx, 1, "Failed to add session pps: %s",
147 sqlite3_errmsg(ctx->db));
148 }
149 sqlite3_free(sql);
150 }
151
152
db_add_session_devinfo(struct hs20_svc * ctx,const char * sessionid,xml_node_t * node)153 static void db_add_session_devinfo(struct hs20_svc *ctx, const char *sessionid,
154 xml_node_t *node)
155 {
156 char *str;
157 char *sql;
158
159 str = xml_node_to_str(ctx->xml, node);
160 if (str == NULL)
161 return;
162 sql = sqlite3_mprintf("UPDATE sessions SET devinfo=%Q WHERE id=%Q",
163 str, sessionid);
164 free(str);
165 if (sql == NULL)
166 return;
167 debug_print(ctx, 1, "DB: %s", sql);
168 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
169 debug_print(ctx, 1, "Failed to add session devinfo: %s",
170 sqlite3_errmsg(ctx->db));
171 }
172 sqlite3_free(sql);
173 }
174
175
db_add_session_devdetail(struct hs20_svc * ctx,const char * sessionid,xml_node_t * node)176 static void db_add_session_devdetail(struct hs20_svc *ctx,
177 const char *sessionid,
178 xml_node_t *node)
179 {
180 char *str;
181 char *sql;
182
183 str = xml_node_to_str(ctx->xml, node);
184 if (str == NULL)
185 return;
186 sql = sqlite3_mprintf("UPDATE sessions SET devdetail=%Q WHERE id=%Q",
187 str, sessionid);
188 free(str);
189 if (sql == NULL)
190 return;
191 debug_print(ctx, 1, "DB: %s", sql);
192 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
193 debug_print(ctx, 1, "Failed to add session devdetail: %s",
194 sqlite3_errmsg(ctx->db));
195 }
196 sqlite3_free(sql);
197 }
198
199
db_remove_session(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid)200 static void db_remove_session(struct hs20_svc *ctx,
201 const char *user, const char *realm,
202 const char *sessionid)
203 {
204 char *sql;
205
206 if (user == NULL || realm == NULL) {
207 sql = sqlite3_mprintf("DELETE FROM sessions WHERE "
208 "id=%Q", sessionid);
209 } else {
210 sql = sqlite3_mprintf("DELETE FROM sessions WHERE "
211 "user=%Q AND realm=%Q AND id=%Q",
212 user, realm, sessionid);
213 }
214 if (sql == NULL)
215 return;
216 debug_print(ctx, 1, "DB: %s", sql);
217 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
218 debug_print(ctx, 1, "Failed to delete session entry from "
219 "sqlite database: %s", sqlite3_errmsg(ctx->db));
220 }
221 sqlite3_free(sql);
222 }
223
224
hs20_eventlog(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid,const char * notes,const char * dump)225 static void hs20_eventlog(struct hs20_svc *ctx,
226 const char *user, const char *realm,
227 const char *sessionid, const char *notes,
228 const char *dump)
229 {
230 char *sql;
231 char *user_buf = NULL, *realm_buf = NULL;
232
233 debug_print(ctx, 1, "eventlog: %s", notes);
234
235 if (user == NULL) {
236 user_buf = db_get_session_val(ctx, NULL, NULL, sessionid,
237 "user");
238 user = user_buf;
239 realm_buf = db_get_session_val(ctx, NULL, NULL, sessionid,
240 "realm");
241 realm = realm_buf;
242 }
243
244 sql = sqlite3_mprintf("INSERT INTO eventlog"
245 "(user,realm,sessionid,timestamp,notes,dump,addr)"
246 " VALUES (%Q,%Q,%Q,"
247 "strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
248 "%Q,%Q,%Q)",
249 user, realm, sessionid, notes,
250 dump ? dump : "", ctx->addr ? ctx->addr : "");
251 free(user_buf);
252 free(realm_buf);
253 if (sql == NULL)
254 return;
255 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
256 debug_print(ctx, 1, "Failed to add eventlog entry into sqlite "
257 "database: %s", sqlite3_errmsg(ctx->db));
258 }
259 sqlite3_free(sql);
260 }
261
262
hs20_eventlog_node(struct hs20_svc * ctx,const char * user,const char * realm,const char * sessionid,const char * notes,xml_node_t * node)263 static void hs20_eventlog_node(struct hs20_svc *ctx,
264 const char *user, const char *realm,
265 const char *sessionid, const char *notes,
266 xml_node_t *node)
267 {
268 char *str;
269
270 if (node)
271 str = xml_node_to_str(ctx->xml, node);
272 else
273 str = NULL;
274 hs20_eventlog(ctx, user, realm, sessionid, notes, str);
275 free(str);
276 }
277
278
db_update_mo_str(struct hs20_svc * ctx,const char * user,const char * realm,const char * name,const char * str)279 static void db_update_mo_str(struct hs20_svc *ctx, const char *user,
280 const char *realm, const char *name,
281 const char *str)
282 {
283 char *sql;
284 if (user == NULL || realm == NULL || name == NULL)
285 return;
286 sql = sqlite3_mprintf("UPDATE users SET %s=%Q "
287 "WHERE identity=%Q AND realm=%Q AND phase2=1",
288 name, str, user, realm);
289 if (sql == NULL)
290 return;
291 debug_print(ctx, 1, "DB: %s", sql);
292 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
293 debug_print(ctx, 1, "Failed to update user MO entry in sqlite "
294 "database: %s", sqlite3_errmsg(ctx->db));
295 }
296 sqlite3_free(sql);
297 }
298
299
db_update_mo(struct hs20_svc * ctx,const char * user,const char * realm,const char * name,xml_node_t * mo)300 static void db_update_mo(struct hs20_svc *ctx, const char *user,
301 const char *realm, const char *name, xml_node_t *mo)
302 {
303 char *str;
304
305 str = xml_node_to_str(ctx->xml, mo);
306 if (str == NULL)
307 return;
308
309 db_update_mo_str(ctx, user, realm, name, str);
310 free(str);
311 }
312
313
add_text_node(struct hs20_svc * ctx,xml_node_t * parent,const char * name,const char * value)314 static void add_text_node(struct hs20_svc *ctx, xml_node_t *parent,
315 const char *name, const char *value)
316 {
317 xml_node_create_text(ctx->xml, parent, NULL, name, value ? value : "");
318 }
319
320
add_text_node_conf(struct hs20_svc * ctx,const char * realm,xml_node_t * parent,const char * name,const char * field)321 static void add_text_node_conf(struct hs20_svc *ctx, const char *realm,
322 xml_node_t *parent, const char *name,
323 const char *field)
324 {
325 char *val;
326 val = db_get_osu_config_val(ctx, realm, field);
327 xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : "");
328 os_free(val);
329 }
330
331
new_password(char * buf,int buflen)332 static int new_password(char *buf, int buflen)
333 {
334 int i;
335
336 if (buflen < 1)
337 return -1;
338 buf[buflen - 1] = '\0';
339 if (os_get_random((unsigned char *) buf, buflen - 1) < 0)
340 return -1;
341
342 for (i = 0; i < buflen - 1; i++) {
343 unsigned char val = buf[i];
344 val %= 2 * 26 + 10;
345 if (val < 26)
346 buf[i] = 'a' + val;
347 else if (val < 2 * 26)
348 buf[i] = 'A' + val - 26;
349 else
350 buf[i] = '0' + val - 2 * 26;
351 }
352
353 return 0;
354 }
355
356
357 struct get_db_field_data {
358 const char *field;
359 char *value;
360 };
361
362
get_db_field(void * ctx,int argc,char * argv[],char * col[])363 static int get_db_field(void *ctx, int argc, char *argv[], char *col[])
364 {
365 struct get_db_field_data *data = ctx;
366 int i;
367
368 for (i = 0; i < argc; i++) {
369 if (os_strcmp(col[i], data->field) == 0 && argv[i]) {
370 os_free(data->value);
371 data->value = os_strdup(argv[i]);
372 break;
373 }
374 }
375
376 return 0;
377 }
378
379
db_get_val(struct hs20_svc * ctx,const char * user,const char * realm,const char * field,int dmacc)380 static char * db_get_val(struct hs20_svc *ctx, const char *user,
381 const char *realm, const char *field, int dmacc)
382 {
383 char *cmd;
384 struct get_db_field_data data;
385
386 cmd = sqlite3_mprintf("SELECT %s FROM users WHERE "
387 "%s=%Q AND realm=%Q AND phase2=1",
388 field, dmacc ? "osu_user" : "identity",
389 user, realm);
390 if (cmd == NULL)
391 return NULL;
392 memset(&data, 0, sizeof(data));
393 data.field = field;
394 if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
395 {
396 debug_print(ctx, 1, "Could not find user '%s'", user);
397 sqlite3_free(cmd);
398 return NULL;
399 }
400 sqlite3_free(cmd);
401
402 debug_print(ctx, 1, "DB: user='%s' realm='%s' field='%s' dmacc=%d --> "
403 "value='%s'", user, realm, field, dmacc, data.value);
404
405 return data.value;
406 }
407
408
db_update_val(struct hs20_svc * ctx,const char * user,const char * realm,const char * field,const char * val,int dmacc)409 static int db_update_val(struct hs20_svc *ctx, const char *user,
410 const char *realm, const char *field,
411 const char *val, int dmacc)
412 {
413 char *cmd;
414 int ret;
415
416 cmd = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE "
417 "%s=%Q AND realm=%Q AND phase2=1",
418 field, val, dmacc ? "osu_user" : "identity", user,
419 realm);
420 if (cmd == NULL)
421 return -1;
422 debug_print(ctx, 1, "DB: %s", cmd);
423 if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
424 debug_print(ctx, 1,
425 "Failed to update user in sqlite database: %s",
426 sqlite3_errmsg(ctx->db));
427 ret = -1;
428 } else {
429 debug_print(ctx, 1,
430 "DB: user='%s' realm='%s' field='%s' set to '%s'",
431 user, realm, field, val);
432 ret = 0;
433 }
434 sqlite3_free(cmd);
435
436 return ret;
437 }
438
439
db_get_session_val(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,const char * field)440 static char * db_get_session_val(struct hs20_svc *ctx, const char *user,
441 const char *realm, const char *session_id,
442 const char *field)
443 {
444 char *cmd;
445 struct get_db_field_data data;
446
447 if (user == NULL || realm == NULL) {
448 cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE "
449 "id=%Q", field, session_id);
450 } else {
451 cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE "
452 "user=%Q AND realm=%Q AND id=%Q",
453 field, user, realm, session_id);
454 }
455 if (cmd == NULL)
456 return NULL;
457 debug_print(ctx, 1, "DB: %s", cmd);
458 memset(&data, 0, sizeof(data));
459 data.field = field;
460 if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
461 {
462 debug_print(ctx, 1, "DB: Could not find session %s: %s",
463 session_id, sqlite3_errmsg(ctx->db));
464 sqlite3_free(cmd);
465 return NULL;
466 }
467 sqlite3_free(cmd);
468
469 debug_print(ctx, 1, "DB: return '%s'", data.value);
470 return data.value;
471 }
472
473
update_password(struct hs20_svc * ctx,const char * user,const char * realm,const char * pw,int dmacc)474 static int update_password(struct hs20_svc *ctx, const char *user,
475 const char *realm, const char *pw, int dmacc)
476 {
477 char *cmd;
478
479 cmd = sqlite3_mprintf("UPDATE users SET password=%Q, "
480 "remediation='' "
481 "WHERE %s=%Q AND phase2=1",
482 pw, dmacc ? "osu_user" : "identity",
483 user);
484 if (cmd == NULL)
485 return -1;
486 debug_print(ctx, 1, "DB: %s", cmd);
487 if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
488 debug_print(ctx, 1, "Failed to update database for user '%s'",
489 user);
490 }
491 sqlite3_free(cmd);
492
493 return 0;
494 }
495
496
add_eap_ttls(struct hs20_svc * ctx,xml_node_t * parent)497 static int add_eap_ttls(struct hs20_svc *ctx, xml_node_t *parent)
498 {
499 xml_node_t *node;
500
501 node = xml_node_create(ctx->xml, parent, NULL, "EAPMethod");
502 if (node == NULL)
503 return -1;
504
505 add_text_node(ctx, node, "EAPType", "21");
506 add_text_node(ctx, node, "InnerMethod", "MS-CHAP-V2");
507
508 return 0;
509 }
510
511
build_username_password(struct hs20_svc * ctx,xml_node_t * parent,const char * user,const char * pw)512 static xml_node_t * build_username_password(struct hs20_svc *ctx,
513 xml_node_t *parent,
514 const char *user, const char *pw)
515 {
516 xml_node_t *node;
517 char *b64;
518
519 node = xml_node_create(ctx->xml, parent, NULL, "UsernamePassword");
520 if (node == NULL)
521 return NULL;
522
523 add_text_node(ctx, node, "Username", user);
524
525 b64 = (char *) base64_encode((unsigned char *) pw, strlen(pw), NULL);
526 if (b64 == NULL)
527 return NULL;
528 add_text_node(ctx, node, "Password", b64);
529 free(b64);
530
531 return node;
532 }
533
534
add_username_password(struct hs20_svc * ctx,xml_node_t * cred,const char * user,const char * pw)535 static int add_username_password(struct hs20_svc *ctx, xml_node_t *cred,
536 const char *user, const char *pw)
537 {
538 xml_node_t *node;
539
540 node = build_username_password(ctx, cred, user, pw);
541 if (node == NULL)
542 return -1;
543
544 add_text_node(ctx, node, "MachineManaged", "TRUE");
545 add_text_node(ctx, node, "SoftTokenApp", "");
546 add_eap_ttls(ctx, node);
547
548 return 0;
549 }
550
551
add_creation_date(struct hs20_svc * ctx,xml_node_t * cred)552 static void add_creation_date(struct hs20_svc *ctx, xml_node_t *cred)
553 {
554 char str[30];
555 time_t now;
556 struct tm tm;
557
558 time(&now);
559 gmtime_r(&now, &tm);
560 snprintf(str, sizeof(str), "%04u-%02u-%02uT%02u:%02u:%02uZ",
561 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
562 tm.tm_hour, tm.tm_min, tm.tm_sec);
563 xml_node_create_text(ctx->xml, cred, NULL, "CreationDate", str);
564 }
565
566
build_credential_pw(struct hs20_svc * ctx,const char * user,const char * realm,const char * pw)567 static xml_node_t * build_credential_pw(struct hs20_svc *ctx,
568 const char *user, const char *realm,
569 const char *pw)
570 {
571 xml_node_t *cred;
572
573 cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential");
574 if (cred == NULL) {
575 debug_print(ctx, 1, "Failed to create Credential node");
576 return NULL;
577 }
578 add_creation_date(ctx, cred);
579 if (add_username_password(ctx, cred, user, pw) < 0) {
580 xml_node_free(ctx->xml, cred);
581 return NULL;
582 }
583 add_text_node(ctx, cred, "Realm", realm);
584
585 return cred;
586 }
587
588
build_credential(struct hs20_svc * ctx,const char * user,const char * realm,char * new_pw,size_t new_pw_len)589 static xml_node_t * build_credential(struct hs20_svc *ctx,
590 const char *user, const char *realm,
591 char *new_pw, size_t new_pw_len)
592 {
593 if (new_password(new_pw, new_pw_len) < 0)
594 return NULL;
595 debug_print(ctx, 1, "Update password to '%s'", new_pw);
596 return build_credential_pw(ctx, user, realm, new_pw);
597 }
598
599
build_credential_cert(struct hs20_svc * ctx,const char * user,const char * realm,const char * cert_fingerprint)600 static xml_node_t * build_credential_cert(struct hs20_svc *ctx,
601 const char *user, const char *realm,
602 const char *cert_fingerprint)
603 {
604 xml_node_t *cred, *cert;
605
606 cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential");
607 if (cred == NULL) {
608 debug_print(ctx, 1, "Failed to create Credential node");
609 return NULL;
610 }
611 add_creation_date(ctx, cred);
612 cert = xml_node_create(ctx->xml, cred, NULL, "DigitalCertificate");
613 add_text_node(ctx, cert, "CertificateType", "x509v3");
614 add_text_node(ctx, cert, "CertSHA256Fingerprint", cert_fingerprint);
615 add_text_node(ctx, cred, "Realm", realm);
616
617 return cred;
618 }
619
620
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)621 static xml_node_t * build_post_dev_data_response(struct hs20_svc *ctx,
622 xml_namespace_t **ret_ns,
623 const char *session_id,
624 const char *status,
625 const char *error_code)
626 {
627 xml_node_t *spp_node = NULL;
628 xml_namespace_t *ns;
629
630 spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
631 "sppPostDevDataResponse");
632 if (spp_node == NULL)
633 return NULL;
634 if (ret_ns)
635 *ret_ns = ns;
636
637 xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
638 xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
639 xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
640
641 if (error_code) {
642 xml_node_t *node;
643 node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
644 if (node)
645 xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
646 error_code);
647 }
648
649 return spp_node;
650 }
651
652
add_update_node(struct hs20_svc * ctx,xml_node_t * spp_node,xml_namespace_t * ns,const char * uri,xml_node_t * upd_node)653 static int add_update_node(struct hs20_svc *ctx, xml_node_t *spp_node,
654 xml_namespace_t *ns, const char *uri,
655 xml_node_t *upd_node)
656 {
657 xml_node_t *node, *tnds;
658 char *str;
659
660 tnds = mo_to_tnds(ctx->xml, upd_node, 0, NULL, NULL);
661 if (!tnds)
662 return -1;
663
664 str = xml_node_to_str(ctx->xml, tnds);
665 xml_node_free(ctx->xml, tnds);
666 if (str == NULL)
667 return -1;
668 node = xml_node_create_text(ctx->xml, spp_node, ns, "updateNode", str);
669 free(str);
670
671 xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", uri);
672
673 return 0;
674 }
675
676
build_sub_rem_resp(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,int machine_rem,int dmacc)677 static xml_node_t * build_sub_rem_resp(struct hs20_svc *ctx,
678 const char *user, const char *realm,
679 const char *session_id,
680 int machine_rem, int dmacc)
681 {
682 xml_namespace_t *ns;
683 xml_node_t *spp_node, *cred;
684 char buf[400];
685 char new_pw[33];
686 char *real_user = NULL;
687 char *status;
688 char *cert;
689
690 if (dmacc) {
691 real_user = db_get_val(ctx, user, realm, "identity", dmacc);
692 if (real_user == NULL) {
693 debug_print(ctx, 1, "Could not find user identity for "
694 "dmacc user '%s'", user);
695 return NULL;
696 }
697 }
698
699 cert = db_get_val(ctx, user, realm, "cert", dmacc);
700 if (cert && cert[0] == '\0')
701 cert = NULL;
702 if (cert) {
703 cred = build_credential_cert(ctx, real_user ? real_user : user,
704 realm, cert);
705 } else {
706 cred = build_credential(ctx, real_user ? real_user : user,
707 realm, new_pw, sizeof(new_pw));
708 }
709 free(real_user);
710 if (!cred) {
711 debug_print(ctx, 1, "Could not build credential");
712 return NULL;
713 }
714
715 status = "Remediation complete, request sppUpdateResponse";
716 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
717 NULL);
718 if (spp_node == NULL) {
719 debug_print(ctx, 1, "Could not build sppPostDevDataResponse");
720 return NULL;
721 }
722
723 snprintf(buf, sizeof(buf),
724 "./Wi-Fi/%s/PerProviderSubscription/Credential1/Credential",
725 realm);
726
727 if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
728 debug_print(ctx, 1, "Could not add update node");
729 xml_node_free(ctx->xml, spp_node);
730 return NULL;
731 }
732
733 hs20_eventlog_node(ctx, user, realm, session_id,
734 machine_rem ? "machine remediation" :
735 "user remediation", cred);
736 xml_node_free(ctx->xml, cred);
737
738 if (cert) {
739 debug_print(ctx, 1, "Certificate credential - no need for DB "
740 "password update on success notification");
741 } else {
742 debug_print(ctx, 1, "Request DB password update on success "
743 "notification");
744 db_add_session(ctx, user, realm, session_id, new_pw, NULL,
745 UPDATE_PASSWORD);
746 }
747
748 return spp_node;
749 }
750
751
machine_remediation(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,int dmacc)752 static xml_node_t * machine_remediation(struct hs20_svc *ctx,
753 const char *user,
754 const char *realm,
755 const char *session_id, int dmacc)
756 {
757 return build_sub_rem_resp(ctx, user, realm, session_id, 1, dmacc);
758 }
759
760
policy_remediation(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,int dmacc)761 static xml_node_t * policy_remediation(struct hs20_svc *ctx,
762 const char *user, const char *realm,
763 const char *session_id, int dmacc)
764 {
765 xml_namespace_t *ns;
766 xml_node_t *spp_node, *policy;
767 char buf[400];
768 const char *status;
769
770 hs20_eventlog(ctx, user, realm, session_id,
771 "requires policy remediation", NULL);
772
773 db_add_session(ctx, user, realm, session_id, NULL, NULL,
774 POLICY_REMEDIATION);
775
776 policy = build_policy(ctx, user, realm, dmacc);
777 if (!policy) {
778 return build_post_dev_data_response(
779 ctx, NULL, session_id,
780 "No update available at this time", NULL);
781 }
782
783 status = "Remediation complete, request sppUpdateResponse";
784 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
785 NULL);
786 if (spp_node == NULL)
787 return NULL;
788
789 snprintf(buf, sizeof(buf),
790 "./Wi-Fi/%s/PerProviderSubscription/Credential1/Policy",
791 realm);
792
793 if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
794 xml_node_free(ctx->xml, spp_node);
795 xml_node_free(ctx->xml, policy);
796 return NULL;
797 }
798
799 hs20_eventlog_node(ctx, user, realm, session_id,
800 "policy update (sub rem)", policy);
801 xml_node_free(ctx->xml, policy);
802
803 return spp_node;
804 }
805
806
browser_remediation(struct hs20_svc * ctx,const char * session_id,const char * redirect_uri,const char * uri)807 static xml_node_t * browser_remediation(struct hs20_svc *ctx,
808 const char *session_id,
809 const char *redirect_uri,
810 const char *uri)
811 {
812 xml_namespace_t *ns;
813 xml_node_t *spp_node, *exec_node;
814
815 if (redirect_uri == NULL) {
816 debug_print(ctx, 1, "Missing redirectURI attribute for user "
817 "remediation");
818 return NULL;
819 }
820 debug_print(ctx, 1, "redirectURI %s", redirect_uri);
821
822 spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
823 NULL);
824 if (spp_node == NULL)
825 return NULL;
826
827 exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
828 xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI",
829 uri);
830 return spp_node;
831 }
832
833
user_remediation(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,const char * redirect_uri)834 static xml_node_t * user_remediation(struct hs20_svc *ctx, const char *user,
835 const char *realm, const char *session_id,
836 const char *redirect_uri)
837 {
838 char uri[300], *val;
839
840 hs20_eventlog(ctx, user, realm, session_id,
841 "requires user remediation", NULL);
842 val = db_get_osu_config_val(ctx, realm, "remediation_url");
843 if (val == NULL)
844 return NULL;
845
846 db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
847 USER_REMEDIATION);
848
849 snprintf(uri, sizeof(uri), "%s%s", val, session_id);
850 os_free(val);
851 return browser_remediation(ctx, session_id, redirect_uri, uri);
852 }
853
854
free_remediation(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,const char * redirect_uri)855 static xml_node_t * free_remediation(struct hs20_svc *ctx,
856 const char *user, const char *realm,
857 const char *session_id,
858 const char *redirect_uri)
859 {
860 char uri[300], *val;
861
862 hs20_eventlog(ctx, user, realm, session_id,
863 "requires free/public account remediation", NULL);
864 val = db_get_osu_config_val(ctx, realm, "free_remediation_url");
865 if (val == NULL)
866 return NULL;
867
868 db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
869 FREE_REMEDIATION);
870
871 snprintf(uri, sizeof(uri), "%s%s", val, session_id);
872 os_free(val);
873 return browser_remediation(ctx, session_id, redirect_uri, uri);
874 }
875
876
no_sub_rem(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id)877 static xml_node_t * no_sub_rem(struct hs20_svc *ctx,
878 const char *user, const char *realm,
879 const char *session_id)
880 {
881 const char *status;
882
883 hs20_eventlog(ctx, user, realm, session_id,
884 "no subscription mediation available", NULL);
885
886 status = "No update available at this time";
887 return build_post_dev_data_response(ctx, NULL, session_id, status,
888 NULL);
889 }
890
891
hs20_subscription_remediation(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,int dmacc,const char * redirect_uri)892 static xml_node_t * hs20_subscription_remediation(struct hs20_svc *ctx,
893 const char *user,
894 const char *realm,
895 const char *session_id,
896 int dmacc,
897 const char *redirect_uri)
898 {
899 char *type, *identity;
900 xml_node_t *ret;
901 char *free_account;
902
903 identity = db_get_val(ctx, user, realm, "identity", dmacc);
904 if (identity == NULL || strlen(identity) == 0) {
905 hs20_eventlog(ctx, user, realm, session_id,
906 "user not found in database for remediation",
907 NULL);
908 os_free(identity);
909 return build_post_dev_data_response(ctx, NULL, session_id,
910 "Error occurred",
911 "Not found");
912 }
913 os_free(identity);
914
915 free_account = db_get_osu_config_val(ctx, realm, "free_account");
916 if (free_account && strcmp(free_account, user) == 0) {
917 free(free_account);
918 return no_sub_rem(ctx, user, realm, session_id);
919 }
920 free(free_account);
921
922 type = db_get_val(ctx, user, realm, "remediation", dmacc);
923 if (type && strcmp(type, "free") != 0) {
924 char *val;
925 int shared = 0;
926 val = db_get_val(ctx, user, realm, "shared", dmacc);
927 if (val)
928 shared = atoi(val);
929 free(val);
930 if (shared) {
931 free(type);
932 return no_sub_rem(ctx, user, realm, session_id);
933 }
934 }
935 if (type && strcmp(type, "user") == 0)
936 ret = user_remediation(ctx, user, realm, session_id,
937 redirect_uri);
938 else if (type && strcmp(type, "free") == 0)
939 ret = free_remediation(ctx, user, realm, session_id,
940 redirect_uri);
941 else if (type && strcmp(type, "policy") == 0)
942 ret = policy_remediation(ctx, user, realm, session_id, dmacc);
943 else
944 ret = machine_remediation(ctx, user, realm, session_id, dmacc);
945 free(type);
946
947 return ret;
948 }
949
950
build_policy(struct hs20_svc * ctx,const char * user,const char * realm,int use_dmacc)951 static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
952 const char *realm, int use_dmacc)
953 {
954 char *policy_id;
955 char fname[200];
956 xml_node_t *policy, *node;
957
958 policy_id = db_get_val(ctx, user, realm, "policy", use_dmacc);
959 if (policy_id == NULL || strlen(policy_id) == 0) {
960 free(policy_id);
961 policy_id = strdup("default");
962 if (policy_id == NULL)
963 return NULL;
964 }
965
966 snprintf(fname, sizeof(fname), "%s/spp/policy/%s.xml",
967 ctx->root_dir, policy_id);
968 free(policy_id);
969 debug_print(ctx, 1, "Use policy file %s", fname);
970
971 policy = node_from_file(ctx->xml, fname);
972 if (policy == NULL)
973 return NULL;
974
975 node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate/URI");
976 if (node) {
977 char *url;
978 url = db_get_osu_config_val(ctx, realm, "policy_url");
979 if (url == NULL) {
980 xml_node_free(ctx->xml, policy);
981 return NULL;
982 }
983 xml_node_set_text(ctx->xml, node, url);
984 free(url);
985 }
986
987 node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate");
988 if (node && use_dmacc) {
989 char *pw;
990 pw = db_get_val(ctx, user, realm, "osu_password", use_dmacc);
991 if (pw == NULL ||
992 build_username_password(ctx, node, user, pw) == NULL) {
993 debug_print(ctx, 1, "Failed to add Policy/PolicyUpdate/"
994 "UsernamePassword");
995 free(pw);
996 xml_node_free(ctx->xml, policy);
997 return NULL;
998 }
999 free(pw);
1000 }
1001
1002 return policy;
1003 }
1004
1005
hs20_policy_update(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id,int dmacc)1006 static xml_node_t * hs20_policy_update(struct hs20_svc *ctx,
1007 const char *user, const char *realm,
1008 const char *session_id, int dmacc)
1009 {
1010 xml_namespace_t *ns;
1011 xml_node_t *spp_node;
1012 xml_node_t *policy;
1013 char buf[400];
1014 const char *status;
1015 char *identity;
1016
1017 identity = db_get_val(ctx, user, realm, "identity", dmacc);
1018 if (identity == NULL || strlen(identity) == 0) {
1019 hs20_eventlog(ctx, user, realm, session_id,
1020 "user not found in database for policy update",
1021 NULL);
1022 os_free(identity);
1023 return build_post_dev_data_response(ctx, NULL, session_id,
1024 "Error occurred",
1025 "Not found");
1026 }
1027 os_free(identity);
1028
1029 policy = build_policy(ctx, user, realm, dmacc);
1030 if (!policy) {
1031 return build_post_dev_data_response(
1032 ctx, NULL, session_id,
1033 "No update available at this time", NULL);
1034 }
1035
1036 db_add_session(ctx, user, realm, session_id, NULL, NULL, POLICY_UPDATE);
1037
1038 status = "Update complete, request sppUpdateResponse";
1039 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1040 NULL);
1041 if (spp_node == NULL)
1042 return NULL;
1043
1044 snprintf(buf, sizeof(buf),
1045 "./Wi-Fi/%s/PerProviderSubscription/Credential1/Policy",
1046 realm);
1047
1048 if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
1049 xml_node_free(ctx->xml, spp_node);
1050 xml_node_free(ctx->xml, policy);
1051 return NULL;
1052 }
1053
1054 hs20_eventlog_node(ctx, user, realm, session_id, "policy update",
1055 policy);
1056 xml_node_free(ctx->xml, policy);
1057
1058 return spp_node;
1059 }
1060
1061
spp_get_mo(struct hs20_svc * ctx,xml_node_t * node,const char * urn,int * valid,char ** ret_err)1062 static xml_node_t * spp_get_mo(struct hs20_svc *ctx, xml_node_t *node,
1063 const char *urn, int *valid, char **ret_err)
1064 {
1065 xml_node_t *child, *tnds, *mo;
1066 const char *name;
1067 char *mo_urn;
1068 char *str;
1069 char fname[200];
1070
1071 *valid = -1;
1072 if (ret_err)
1073 *ret_err = NULL;
1074
1075 xml_node_for_each_child(ctx->xml, child, node) {
1076 xml_node_for_each_check(ctx->xml, child);
1077 name = xml_node_get_localname(ctx->xml, child);
1078 if (strcmp(name, "moContainer") != 0)
1079 continue;
1080 mo_urn = xml_node_get_attr_value_ns(ctx->xml, child, SPP_NS_URI,
1081 "moURN");
1082 if (strcasecmp(urn, mo_urn) == 0) {
1083 xml_node_get_attr_value_free(ctx->xml, mo_urn);
1084 break;
1085 }
1086 xml_node_get_attr_value_free(ctx->xml, mo_urn);
1087 }
1088
1089 if (child == NULL)
1090 return NULL;
1091
1092 debug_print(ctx, 1, "moContainer text for %s", urn);
1093 debug_dump_node(ctx, "moContainer", child);
1094
1095 str = xml_node_get_text(ctx->xml, child);
1096 debug_print(ctx, 1, "moContainer payload: '%s'", str);
1097 tnds = xml_node_from_buf(ctx->xml, str);
1098 xml_node_get_text_free(ctx->xml, str);
1099 if (tnds == NULL) {
1100 debug_print(ctx, 1, "could not parse moContainer text");
1101 return NULL;
1102 }
1103
1104 snprintf(fname, sizeof(fname), "%s/spp/dm_ddf-v1_2.dtd", ctx->root_dir);
1105 if (xml_validate_dtd(ctx->xml, tnds, fname, ret_err) == 0)
1106 *valid = 1;
1107 else if (ret_err && *ret_err &&
1108 os_strcmp(*ret_err, "No declaration for attribute xmlns of element MgmtTree\n") == 0) {
1109 free(*ret_err);
1110 debug_print(ctx, 1, "Ignore OMA-DM DDF DTD validation error for MgmtTree namespace declaration with xmlns attribute");
1111 *ret_err = NULL;
1112 *valid = 1;
1113 } else
1114 *valid = 0;
1115
1116 mo = tnds_to_mo(ctx->xml, tnds);
1117 xml_node_free(ctx->xml, tnds);
1118 if (mo == NULL) {
1119 debug_print(ctx, 1, "invalid moContainer for %s", urn);
1120 }
1121
1122 return mo;
1123 }
1124
1125
spp_exec_upload_mo(struct hs20_svc * ctx,const char * session_id,const char * urn)1126 static xml_node_t * spp_exec_upload_mo(struct hs20_svc *ctx,
1127 const char *session_id, const char *urn)
1128 {
1129 xml_namespace_t *ns;
1130 xml_node_t *spp_node, *node, *exec_node;
1131
1132 spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
1133 NULL);
1134 if (spp_node == NULL)
1135 return NULL;
1136
1137 exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
1138
1139 node = xml_node_create(ctx->xml, exec_node, ns, "uploadMO");
1140 xml_node_add_attr(ctx->xml, node, ns, "moURN", urn);
1141
1142 return spp_node;
1143 }
1144
1145
hs20_subscription_registration(struct hs20_svc * ctx,const char * realm,const char * session_id,const char * redirect_uri)1146 static xml_node_t * hs20_subscription_registration(struct hs20_svc *ctx,
1147 const char *realm,
1148 const char *session_id,
1149 const char *redirect_uri)
1150 {
1151 xml_namespace_t *ns;
1152 xml_node_t *spp_node, *exec_node;
1153 char uri[300], *val;
1154
1155 if (db_add_session(ctx, NULL, realm, session_id, NULL, redirect_uri,
1156 SUBSCRIPTION_REGISTRATION) < 0)
1157 return NULL;
1158 val = db_get_osu_config_val(ctx, realm, "signup_url");
1159 if (val == NULL)
1160 return NULL;
1161
1162 spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
1163 NULL);
1164 if (spp_node == NULL)
1165 return NULL;
1166
1167 exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
1168
1169 snprintf(uri, sizeof(uri), "%s%s", val, session_id);
1170 os_free(val);
1171 xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI",
1172 uri);
1173 return spp_node;
1174 }
1175
1176
hs20_user_input_remediation(struct hs20_svc * ctx,const char * user,const char * realm,int dmacc,const char * session_id)1177 static xml_node_t * hs20_user_input_remediation(struct hs20_svc *ctx,
1178 const char *user,
1179 const char *realm, int dmacc,
1180 const char *session_id)
1181 {
1182 return build_sub_rem_resp(ctx, user, realm, session_id, 0, dmacc);
1183 }
1184
1185
db_get_osu_config_val(struct hs20_svc * ctx,const char * realm,const char * field)1186 static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm,
1187 const char *field)
1188 {
1189 char *cmd;
1190 struct get_db_field_data data;
1191
1192 cmd = sqlite3_mprintf("SELECT value FROM osu_config WHERE realm=%Q AND "
1193 "field=%Q", realm, field);
1194 if (cmd == NULL)
1195 return NULL;
1196 debug_print(ctx, 1, "DB: %s", cmd);
1197 memset(&data, 0, sizeof(data));
1198 data.field = "value";
1199 if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
1200 {
1201 debug_print(ctx, 1, "DB: Could not find osu_config %s: %s",
1202 realm, sqlite3_errmsg(ctx->db));
1203 sqlite3_free(cmd);
1204 return NULL;
1205 }
1206 sqlite3_free(cmd);
1207
1208 debug_print(ctx, 1, "DB: return '%s'", data.value);
1209 return data.value;
1210 }
1211
1212
build_pps(struct hs20_svc * ctx,const char * user,const char * realm,const char * pw,const char * cert,int machine_managed)1213 static xml_node_t * build_pps(struct hs20_svc *ctx,
1214 const char *user, const char *realm,
1215 const char *pw, const char *cert,
1216 int machine_managed)
1217 {
1218 xml_node_t *pps, *c, *trust, *aaa, *aaa1, *upd, *homesp;
1219 xml_node_t *cred, *eap, *userpw;
1220
1221 pps = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
1222 "PerProviderSubscription");
1223 if (pps == NULL)
1224 return NULL;
1225
1226 add_text_node(ctx, pps, "UpdateIdentifier", "1");
1227
1228 c = xml_node_create(ctx->xml, pps, NULL, "Credential1");
1229
1230 add_text_node(ctx, c, "CredentialPriority", "1");
1231
1232 aaa = xml_node_create(ctx->xml, c, NULL, "AAAServerTrustRoot");
1233 aaa1 = xml_node_create(ctx->xml, aaa, NULL, "AAA1");
1234 add_text_node_conf(ctx, realm, aaa1, "CertURL",
1235 "aaa_trust_root_cert_url");
1236 add_text_node_conf(ctx, realm, aaa1, "CertSHA256Fingerprint",
1237 "aaa_trust_root_cert_fingerprint");
1238
1239 upd = xml_node_create(ctx->xml, c, NULL, "SubscriptionUpdate");
1240 add_text_node(ctx, upd, "UpdateInterval", "4294967295");
1241 add_text_node(ctx, upd, "UpdateMethod", "ClientInitiated");
1242 add_text_node(ctx, upd, "Restriction", "HomeSP");
1243 add_text_node_conf(ctx, realm, upd, "URI", "spp_http_auth_url");
1244 trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
1245 add_text_node_conf(ctx, realm, trust, "CertURL", "trust_root_cert_url");
1246 add_text_node_conf(ctx, realm, trust, "CertSHA256Fingerprint",
1247 "trust_root_cert_fingerprint");
1248
1249 homesp = xml_node_create(ctx->xml, c, NULL, "HomeSP");
1250 add_text_node_conf(ctx, realm, homesp, "FriendlyName", "friendly_name");
1251 add_text_node_conf(ctx, realm, homesp, "FQDN", "fqdn");
1252
1253 xml_node_create(ctx->xml, c, NULL, "SubscriptionParameters");
1254
1255 cred = xml_node_create(ctx->xml, c, NULL, "Credential");
1256 add_creation_date(ctx, cred);
1257 if (cert) {
1258 xml_node_t *dc;
1259 dc = xml_node_create(ctx->xml, cred, NULL,
1260 "DigitalCertificate");
1261 add_text_node(ctx, dc, "CertificateType", "x509v3");
1262 add_text_node(ctx, dc, "CertSHA256Fingerprint", cert);
1263 } else {
1264 userpw = build_username_password(ctx, cred, user, pw);
1265 add_text_node(ctx, userpw, "MachineManaged",
1266 machine_managed ? "TRUE" : "FALSE");
1267 eap = xml_node_create(ctx->xml, userpw, NULL, "EAPMethod");
1268 add_text_node(ctx, eap, "EAPType", "21");
1269 add_text_node(ctx, eap, "InnerMethod", "MS-CHAP-V2");
1270 }
1271 add_text_node(ctx, cred, "Realm", realm);
1272
1273 return pps;
1274 }
1275
1276
spp_exec_get_certificate(struct hs20_svc * ctx,const char * session_id,const char * user,const char * realm)1277 static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx,
1278 const char *session_id,
1279 const char *user,
1280 const char *realm)
1281 {
1282 xml_namespace_t *ns;
1283 xml_node_t *spp_node, *enroll, *exec_node;
1284 char *val;
1285 char password[11];
1286 char *b64;
1287
1288 if (new_password(password, sizeof(password)) < 0)
1289 return NULL;
1290
1291 spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
1292 NULL);
1293 if (spp_node == NULL)
1294 return NULL;
1295
1296 exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
1297
1298 enroll = xml_node_create(ctx->xml, exec_node, ns, "getCertificate");
1299 xml_node_add_attr(ctx->xml, enroll, NULL, "enrollmentProtocol", "EST");
1300
1301 val = db_get_osu_config_val(ctx, realm, "est_url");
1302 xml_node_create_text(ctx->xml, enroll, ns, "enrollmentServerURI",
1303 val ? val : "");
1304 os_free(val);
1305 xml_node_create_text(ctx->xml, enroll, ns, "estUserID", user);
1306
1307 b64 = (char *) base64_encode((unsigned char *) password,
1308 strlen(password), NULL);
1309 if (b64 == NULL) {
1310 xml_node_free(ctx->xml, spp_node);
1311 return NULL;
1312 }
1313 xml_node_create_text(ctx->xml, enroll, ns, "estPassword", b64);
1314 free(b64);
1315
1316 db_update_session_password(ctx, user, realm, session_id, password);
1317
1318 return spp_node;
1319 }
1320
1321
hs20_user_input_registration(struct hs20_svc * ctx,const char * session_id,int enrollment_done)1322 static xml_node_t * hs20_user_input_registration(struct hs20_svc *ctx,
1323 const char *session_id,
1324 int enrollment_done)
1325 {
1326 xml_namespace_t *ns;
1327 xml_node_t *spp_node, *node = NULL;
1328 xml_node_t *pps, *tnds;
1329 char buf[400];
1330 char *str;
1331 char *user, *realm, *pw, *type, *mm;
1332 const char *status;
1333 int cert = 0;
1334 int machine_managed = 0;
1335 char *fingerprint;
1336
1337 user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
1338 realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
1339 pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
1340
1341 if (!user || !realm || !pw) {
1342 debug_print(ctx, 1, "Could not find session info from DB for "
1343 "the new subscription");
1344 free(user);
1345 free(realm);
1346 free(pw);
1347 return NULL;
1348 }
1349
1350 mm = db_get_session_val(ctx, NULL, NULL, session_id, "machine_managed");
1351 if (mm && atoi(mm))
1352 machine_managed = 1;
1353 free(mm);
1354
1355 type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
1356 if (type && strcmp(type, "cert") == 0)
1357 cert = 1;
1358 free(type);
1359
1360 if (cert && !enrollment_done) {
1361 xml_node_t *ret;
1362 hs20_eventlog(ctx, user, realm, session_id,
1363 "request client certificate enrollment", NULL);
1364 ret = spp_exec_get_certificate(ctx, session_id, user, realm);
1365 free(user);
1366 free(realm);
1367 free(pw);
1368 return ret;
1369 }
1370
1371 if (!cert && strlen(pw) == 0) {
1372 machine_managed = 1;
1373 free(pw);
1374 pw = malloc(11);
1375 if (pw == NULL || new_password(pw, 11) < 0) {
1376 free(user);
1377 free(realm);
1378 free(pw);
1379 return NULL;
1380 }
1381 }
1382
1383 status = "Provisioning complete, request sppUpdateResponse";
1384 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1385 NULL);
1386 if (spp_node == NULL)
1387 return NULL;
1388
1389 fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
1390 pps = build_pps(ctx, user, realm, pw,
1391 fingerprint ? fingerprint : NULL, machine_managed);
1392 free(fingerprint);
1393 if (!pps) {
1394 xml_node_free(ctx->xml, spp_node);
1395 free(user);
1396 free(realm);
1397 free(pw);
1398 return NULL;
1399 }
1400
1401 debug_print(ctx, 1, "Request DB subscription registration on success "
1402 "notification");
1403 if (machine_managed) {
1404 db_update_session_password(ctx, user, realm, session_id, pw);
1405 db_update_session_machine_managed(ctx, user, realm, session_id,
1406 machine_managed);
1407 }
1408 db_add_session_pps(ctx, user, realm, session_id, pps);
1409
1410 hs20_eventlog_node(ctx, user, realm, session_id,
1411 "new subscription", pps);
1412 free(user);
1413 free(pw);
1414
1415 tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL);
1416 xml_node_free(ctx->xml, pps);
1417 if (!tnds) {
1418 xml_node_free(ctx->xml, spp_node);
1419 free(realm);
1420 return NULL;
1421 }
1422
1423 str = xml_node_to_str(ctx->xml, tnds);
1424 xml_node_free(ctx->xml, tnds);
1425 if (str == NULL) {
1426 xml_node_free(ctx->xml, spp_node);
1427 free(realm);
1428 return NULL;
1429 }
1430
1431 node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str);
1432 free(str);
1433 snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm);
1434 free(realm);
1435 xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf);
1436 xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS);
1437
1438 return spp_node;
1439 }
1440
1441
hs20_user_input_free_remediation(struct hs20_svc * ctx,const char * user,const char * realm,const char * session_id)1442 static xml_node_t * hs20_user_input_free_remediation(struct hs20_svc *ctx,
1443 const char *user,
1444 const char *realm,
1445 const char *session_id)
1446 {
1447 xml_namespace_t *ns;
1448 xml_node_t *spp_node;
1449 xml_node_t *cred;
1450 char buf[400];
1451 char *status;
1452 char *free_account, *pw;
1453
1454 free_account = db_get_osu_config_val(ctx, realm, "free_account");
1455 if (free_account == NULL)
1456 return NULL;
1457 pw = db_get_val(ctx, free_account, realm, "password", 0);
1458 if (pw == NULL) {
1459 free(free_account);
1460 return NULL;
1461 }
1462
1463 cred = build_credential_pw(ctx, free_account, realm, pw);
1464 free(free_account);
1465 free(pw);
1466 if (!cred) {
1467 xml_node_free(ctx->xml, cred);
1468 return NULL;
1469 }
1470
1471 status = "Remediation complete, request sppUpdateResponse";
1472 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1473 NULL);
1474 if (spp_node == NULL)
1475 return NULL;
1476
1477 snprintf(buf, sizeof(buf),
1478 "./Wi-Fi/%s/PerProviderSubscription/Credential1/Credential",
1479 realm);
1480
1481 if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
1482 xml_node_free(ctx->xml, spp_node);
1483 return NULL;
1484 }
1485
1486 hs20_eventlog_node(ctx, user, realm, session_id,
1487 "free/public remediation", cred);
1488 xml_node_free(ctx->xml, cred);
1489
1490 return spp_node;
1491 }
1492
1493
hs20_user_input_complete(struct hs20_svc * ctx,const char * user,const char * realm,int dmacc,const char * session_id)1494 static xml_node_t * hs20_user_input_complete(struct hs20_svc *ctx,
1495 const char *user,
1496 const char *realm, int dmacc,
1497 const char *session_id)
1498 {
1499 char *val;
1500 enum hs20_session_operation oper;
1501
1502 val = db_get_session_val(ctx, user, realm, session_id, "operation");
1503 if (val == NULL) {
1504 debug_print(ctx, 1, "No session %s found to continue",
1505 session_id);
1506 return NULL;
1507 }
1508 oper = atoi(val);
1509 free(val);
1510
1511 if (oper == USER_REMEDIATION) {
1512 return hs20_user_input_remediation(ctx, user, realm, dmacc,
1513 session_id);
1514 }
1515
1516 if (oper == FREE_REMEDIATION) {
1517 return hs20_user_input_free_remediation(ctx, user, realm,
1518 session_id);
1519 }
1520
1521 if (oper == SUBSCRIPTION_REGISTRATION) {
1522 return hs20_user_input_registration(ctx, session_id, 0);
1523 }
1524
1525 debug_print(ctx, 1, "User session %s not in state for user input "
1526 "completion", session_id);
1527 return NULL;
1528 }
1529
1530
hs20_cert_enroll_completed(struct hs20_svc * ctx,const char * user,const char * realm,int dmacc,const char * session_id)1531 static xml_node_t * hs20_cert_enroll_completed(struct hs20_svc *ctx,
1532 const char *user,
1533 const char *realm, int dmacc,
1534 const char *session_id)
1535 {
1536 char *val;
1537 enum hs20_session_operation oper;
1538
1539 val = db_get_session_val(ctx, user, realm, session_id, "operation");
1540 if (val == NULL) {
1541 debug_print(ctx, 1, "No session %s found to continue",
1542 session_id);
1543 return NULL;
1544 }
1545 oper = atoi(val);
1546 free(val);
1547
1548 if (oper == SUBSCRIPTION_REGISTRATION)
1549 return hs20_user_input_registration(ctx, session_id, 1);
1550
1551 debug_print(ctx, 1, "User session %s not in state for certificate "
1552 "enrollment completion", session_id);
1553 return NULL;
1554 }
1555
1556
hs20_cert_enroll_failed(struct hs20_svc * ctx,const char * user,const char * realm,int dmacc,const char * session_id)1557 static xml_node_t * hs20_cert_enroll_failed(struct hs20_svc *ctx,
1558 const char *user,
1559 const char *realm, int dmacc,
1560 const char *session_id)
1561 {
1562 char *val;
1563 enum hs20_session_operation oper;
1564 xml_node_t *spp_node, *node;
1565 char *status;
1566 xml_namespace_t *ns;
1567
1568 val = db_get_session_val(ctx, user, realm, session_id, "operation");
1569 if (val == NULL) {
1570 debug_print(ctx, 1, "No session %s found to continue",
1571 session_id);
1572 return NULL;
1573 }
1574 oper = atoi(val);
1575 free(val);
1576
1577 if (oper != SUBSCRIPTION_REGISTRATION) {
1578 debug_print(ctx, 1, "User session %s not in state for "
1579 "enrollment failure", session_id);
1580 return NULL;
1581 }
1582
1583 status = "Error occurred";
1584 spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
1585 NULL);
1586 if (spp_node == NULL)
1587 return NULL;
1588 node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
1589 xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
1590 "Credentials cannot be provisioned at this time");
1591 db_remove_session(ctx, user, realm, session_id);
1592
1593 return spp_node;
1594 }
1595
1596
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)1597 static xml_node_t * hs20_spp_post_dev_data(struct hs20_svc *ctx,
1598 xml_node_t *node,
1599 const char *user,
1600 const char *realm,
1601 const char *session_id,
1602 int dmacc)
1603 {
1604 const char *req_reason;
1605 char *redirect_uri = NULL;
1606 char *req_reason_buf = NULL;
1607 char str[200];
1608 xml_node_t *ret = NULL, *devinfo = NULL, *devdetail = NULL;
1609 xml_node_t *mo;
1610 char *version;
1611 int valid;
1612 char *supp, *pos;
1613 char *err;
1614
1615 version = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
1616 "sppVersion");
1617 if (version == NULL || strstr(version, "1.0") == NULL) {
1618 ret = build_post_dev_data_response(
1619 ctx, NULL, session_id, "Error occurred",
1620 "SPP version not supported");
1621 hs20_eventlog_node(ctx, user, realm, session_id,
1622 "Unsupported sppVersion", ret);
1623 xml_node_get_attr_value_free(ctx->xml, version);
1624 return ret;
1625 }
1626 xml_node_get_attr_value_free(ctx->xml, version);
1627
1628 mo = get_node(ctx->xml, node, "supportedMOList");
1629 if (mo == NULL) {
1630 ret = build_post_dev_data_response(
1631 ctx, NULL, session_id, "Error occurred",
1632 "Other");
1633 hs20_eventlog_node(ctx, user, realm, session_id,
1634 "No supportedMOList element", ret);
1635 return ret;
1636 }
1637 supp = xml_node_get_text(ctx->xml, mo);
1638 for (pos = supp; pos && *pos; pos++)
1639 *pos = tolower(*pos);
1640 if (supp == NULL ||
1641 strstr(supp, URN_OMA_DM_DEVINFO) == NULL ||
1642 strstr(supp, URN_OMA_DM_DEVDETAIL) == NULL ||
1643 strstr(supp, URN_HS20_PPS) == NULL) {
1644 xml_node_get_text_free(ctx->xml, supp);
1645 ret = build_post_dev_data_response(
1646 ctx, NULL, session_id, "Error occurred",
1647 "One or more mandatory MOs not supported");
1648 hs20_eventlog_node(ctx, user, realm, session_id,
1649 "Unsupported MOs", ret);
1650 return ret;
1651 }
1652 xml_node_get_text_free(ctx->xml, supp);
1653
1654 req_reason_buf = xml_node_get_attr_value(ctx->xml, node,
1655 "requestReason");
1656 if (req_reason_buf == NULL) {
1657 debug_print(ctx, 1, "No requestReason attribute");
1658 return NULL;
1659 }
1660 req_reason = req_reason_buf;
1661
1662 redirect_uri = xml_node_get_attr_value(ctx->xml, node, "redirectURI");
1663
1664 debug_print(ctx, 1, "requestReason: %s sessionID: %s redirectURI: %s",
1665 req_reason, session_id, redirect_uri);
1666 snprintf(str, sizeof(str), "sppPostDevData: requestReason=%s",
1667 req_reason);
1668 hs20_eventlog(ctx, user, realm, session_id, str, NULL);
1669
1670 devinfo = spp_get_mo(ctx, node, URN_OMA_DM_DEVINFO, &valid, &err);
1671 if (devinfo == NULL) {
1672 ret = build_post_dev_data_response(ctx, NULL, session_id,
1673 "Error occurred", "Other");
1674 hs20_eventlog_node(ctx, user, realm, session_id,
1675 "No DevInfo moContainer in sppPostDevData",
1676 ret);
1677 os_free(err);
1678 goto out;
1679 }
1680
1681 hs20_eventlog_node(ctx, user, realm, session_id,
1682 "Received DevInfo MO", devinfo);
1683 if (valid == 0) {
1684 hs20_eventlog(ctx, user, realm, session_id,
1685 "OMA-DM DDF DTD validation errors in DevInfo MO",
1686 err);
1687 ret = build_post_dev_data_response(ctx, NULL, session_id,
1688 "Error occurred", "Other");
1689 os_free(err);
1690 goto out;
1691 }
1692 os_free(err);
1693 if (user)
1694 db_update_mo(ctx, user, realm, "devinfo", devinfo);
1695
1696 devdetail = spp_get_mo(ctx, node, URN_OMA_DM_DEVDETAIL, &valid, &err);
1697 if (devdetail == NULL) {
1698 ret = build_post_dev_data_response(ctx, NULL, session_id,
1699 "Error occurred", "Other");
1700 hs20_eventlog_node(ctx, user, realm, session_id,
1701 "No DevDetail moContainer in sppPostDevData",
1702 ret);
1703 os_free(err);
1704 goto out;
1705 }
1706
1707 hs20_eventlog_node(ctx, user, realm, session_id,
1708 "Received DevDetail MO", devdetail);
1709 if (valid == 0) {
1710 hs20_eventlog(ctx, user, realm, session_id,
1711 "OMA-DM DDF DTD validation errors "
1712 "in DevDetail MO", err);
1713 ret = build_post_dev_data_response(ctx, NULL, session_id,
1714 "Error occurred", "Other");
1715 os_free(err);
1716 goto out;
1717 }
1718 os_free(err);
1719 if (user)
1720 db_update_mo(ctx, user, realm, "devdetail", devdetail);
1721
1722 if (user)
1723 mo = spp_get_mo(ctx, node, URN_HS20_PPS, &valid, &err);
1724 else {
1725 mo = NULL;
1726 err = NULL;
1727 }
1728 if (user && mo) {
1729 hs20_eventlog_node(ctx, user, realm, session_id,
1730 "Received PPS MO", mo);
1731 if (valid == 0) {
1732 hs20_eventlog(ctx, user, realm, session_id,
1733 "OMA-DM DDF DTD validation errors "
1734 "in PPS MO", err);
1735 xml_node_get_attr_value_free(ctx->xml, redirect_uri);
1736 os_free(err);
1737 return build_post_dev_data_response(
1738 ctx, NULL, session_id,
1739 "Error occurred", "Other");
1740 }
1741 db_update_mo(ctx, user, realm, "pps", mo);
1742 db_update_val(ctx, user, realm, "fetch_pps", "0", dmacc);
1743 xml_node_free(ctx->xml, mo);
1744 }
1745 os_free(err);
1746
1747 if (user && !mo) {
1748 char *fetch;
1749 int fetch_pps;
1750
1751 fetch = db_get_val(ctx, user, realm, "fetch_pps", dmacc);
1752 fetch_pps = fetch ? atoi(fetch) : 0;
1753 free(fetch);
1754
1755 if (fetch_pps) {
1756 enum hs20_session_operation oper;
1757 if (strcasecmp(req_reason, "Subscription remediation")
1758 == 0)
1759 oper = CONTINUE_SUBSCRIPTION_REMEDIATION;
1760 else if (strcasecmp(req_reason, "Policy update") == 0)
1761 oper = CONTINUE_POLICY_UPDATE;
1762 else
1763 oper = NO_OPERATION;
1764 if (db_add_session(ctx, user, realm, session_id, NULL,
1765 NULL, oper) < 0)
1766 goto out;
1767
1768 ret = spp_exec_upload_mo(ctx, session_id,
1769 URN_HS20_PPS);
1770 hs20_eventlog_node(ctx, user, realm, session_id,
1771 "request PPS MO upload",
1772 ret);
1773 goto out;
1774 }
1775 }
1776
1777 if (user && strcasecmp(req_reason, "MO upload") == 0) {
1778 char *val = db_get_session_val(ctx, user, realm, session_id,
1779 "operation");
1780 enum hs20_session_operation oper;
1781 if (!val) {
1782 debug_print(ctx, 1, "No session %s found to continue",
1783 session_id);
1784 goto out;
1785 }
1786 oper = atoi(val);
1787 free(val);
1788 if (oper == CONTINUE_SUBSCRIPTION_REMEDIATION)
1789 req_reason = "Subscription remediation";
1790 else if (oper == CONTINUE_POLICY_UPDATE)
1791 req_reason = "Policy update";
1792 else {
1793 debug_print(ctx, 1,
1794 "No pending operation in session %s",
1795 session_id);
1796 goto out;
1797 }
1798 }
1799
1800 if (strcasecmp(req_reason, "Subscription registration") == 0) {
1801 ret = hs20_subscription_registration(ctx, realm, session_id,
1802 redirect_uri);
1803 hs20_eventlog_node(ctx, user, realm, session_id,
1804 "subscription registration response",
1805 ret);
1806 goto out;
1807 }
1808 if (user && strcasecmp(req_reason, "Subscription remediation") == 0) {
1809 ret = hs20_subscription_remediation(ctx, user, realm,
1810 session_id, dmacc,
1811 redirect_uri);
1812 hs20_eventlog_node(ctx, user, realm, session_id,
1813 "subscription remediation response",
1814 ret);
1815 goto out;
1816 }
1817 if (user && strcasecmp(req_reason, "Policy update") == 0) {
1818 ret = hs20_policy_update(ctx, user, realm, session_id, dmacc);
1819 hs20_eventlog_node(ctx, user, realm, session_id,
1820 "policy update response",
1821 ret);
1822 goto out;
1823 }
1824
1825 if (strcasecmp(req_reason, "User input completed") == 0) {
1826 db_add_session_devinfo(ctx, session_id, devinfo);
1827 db_add_session_devdetail(ctx, session_id, devdetail);
1828 ret = hs20_user_input_complete(ctx, user, realm, dmacc,
1829 session_id);
1830 hs20_eventlog_node(ctx, user, realm, session_id,
1831 "user input completed response", ret);
1832 goto out;
1833 }
1834
1835 if (strcasecmp(req_reason, "Certificate enrollment completed") == 0) {
1836 ret = hs20_cert_enroll_completed(ctx, user, realm, dmacc,
1837 session_id);
1838 hs20_eventlog_node(ctx, user, realm, session_id,
1839 "certificate enrollment response", ret);
1840 goto out;
1841 }
1842
1843 if (strcasecmp(req_reason, "Certificate enrollment failed") == 0) {
1844 ret = hs20_cert_enroll_failed(ctx, user, realm, dmacc,
1845 session_id);
1846 hs20_eventlog_node(ctx, user, realm, session_id,
1847 "certificate enrollment failed response",
1848 ret);
1849 goto out;
1850 }
1851
1852 debug_print(ctx, 1, "Unsupported requestReason '%s' user '%s'",
1853 req_reason, user);
1854 out:
1855 xml_node_get_attr_value_free(ctx->xml, req_reason_buf);
1856 xml_node_get_attr_value_free(ctx->xml, redirect_uri);
1857 if (devinfo)
1858 xml_node_free(ctx->xml, devinfo);
1859 if (devdetail)
1860 xml_node_free(ctx->xml, devdetail);
1861 return ret;
1862 }
1863
1864
build_spp_exchange_complete(struct hs20_svc * ctx,const char * session_id,const char * status,const char * error_code)1865 static xml_node_t * build_spp_exchange_complete(struct hs20_svc *ctx,
1866 const char *session_id,
1867 const char *status,
1868 const char *error_code)
1869 {
1870 xml_namespace_t *ns;
1871 xml_node_t *spp_node, *node;
1872
1873 spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
1874 "sppExchangeComplete");
1875
1876
1877 xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
1878 xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
1879 xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
1880
1881 if (error_code) {
1882 node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
1883 xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
1884 error_code);
1885 }
1886
1887 return spp_node;
1888 }
1889
1890
add_subscription(struct hs20_svc * ctx,const char * session_id)1891 static int add_subscription(struct hs20_svc *ctx, const char *session_id)
1892 {
1893 char *user, *realm, *pw, *pw_mm, *pps, *str;
1894 char *sql;
1895 int ret = -1;
1896 char *free_account;
1897 int free_acc;
1898 char *type;
1899 int cert = 0;
1900 char *cert_pem, *fingerprint;
1901
1902 user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
1903 realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
1904 pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
1905 pw_mm = db_get_session_val(ctx, NULL, NULL, session_id,
1906 "machine_managed");
1907 pps = db_get_session_val(ctx, NULL, NULL, session_id, "pps");
1908 cert_pem = db_get_session_val(ctx, NULL, NULL, session_id, "cert_pem");
1909 fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
1910 type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
1911 if (type && strcmp(type, "cert") == 0)
1912 cert = 1;
1913 free(type);
1914
1915 if (!user || !realm || !pw) {
1916 debug_print(ctx, 1, "Could not find session info from DB for "
1917 "the new subscription");
1918 goto out;
1919 }
1920
1921 free_account = db_get_osu_config_val(ctx, realm, "free_account");
1922 free_acc = free_account && strcmp(free_account, user) == 0;
1923 free(free_account);
1924
1925 debug_print(ctx, 1,
1926 "New subscription: user='%s' realm='%s' free_acc=%d",
1927 user, realm, free_acc);
1928 debug_print(ctx, 1, "New subscription: pps='%s'", pps);
1929
1930 sql = sqlite3_mprintf("UPDATE eventlog SET user=%Q, realm=%Q WHERE "
1931 "sessionid=%Q AND (user='' OR user IS NULL)",
1932 user, realm, session_id);
1933 if (sql) {
1934 debug_print(ctx, 1, "DB: %s", sql);
1935 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
1936 debug_print(ctx, 1, "Failed to update eventlog in "
1937 "sqlite database: %s",
1938 sqlite3_errmsg(ctx->db));
1939 }
1940 sqlite3_free(sql);
1941 }
1942
1943 if (free_acc) {
1944 hs20_eventlog(ctx, user, realm, session_id,
1945 "completed shared free account registration",
1946 NULL);
1947 ret = 0;
1948 goto out;
1949 }
1950
1951 sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,"
1952 "methods,cert,cert_pem,machine_managed) VALUES "
1953 "(%Q,%Q,1,%Q,%Q,%Q,%d)",
1954 user, realm, cert ? "TLS" : "TTLS-MSCHAPV2",
1955 fingerprint ? fingerprint : "",
1956 cert_pem ? cert_pem : "",
1957 pw_mm && atoi(pw_mm) ? 1 : 0);
1958 if (sql == NULL)
1959 goto out;
1960 debug_print(ctx, 1, "DB: %s", sql);
1961 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
1962 debug_print(ctx, 1, "Failed to add user in sqlite database: %s",
1963 sqlite3_errmsg(ctx->db));
1964 sqlite3_free(sql);
1965 goto out;
1966 }
1967 sqlite3_free(sql);
1968
1969 if (cert)
1970 ret = 0;
1971 else
1972 ret = update_password(ctx, user, realm, pw, 0);
1973 if (ret < 0) {
1974 sql = sqlite3_mprintf("DELETE FROM users WHERE identity=%Q AND "
1975 "realm=%Q AND phase2=1",
1976 user, realm);
1977 if (sql) {
1978 debug_print(ctx, 1, "DB: %s", sql);
1979 sqlite3_exec(ctx->db, sql, NULL, NULL, NULL);
1980 sqlite3_free(sql);
1981 }
1982 }
1983
1984 if (pps)
1985 db_update_mo_str(ctx, user, realm, "pps", pps);
1986
1987 str = db_get_session_val(ctx, NULL, NULL, session_id, "devinfo");
1988 if (str) {
1989 db_update_mo_str(ctx, user, realm, "devinfo", str);
1990 free(str);
1991 }
1992
1993 str = db_get_session_val(ctx, NULL, NULL, session_id, "devdetail");
1994 if (str) {
1995 db_update_mo_str(ctx, user, realm, "devdetail", str);
1996 free(str);
1997 }
1998
1999 if (ret == 0) {
2000 hs20_eventlog(ctx, user, realm, session_id,
2001 "completed subscription registration", NULL);
2002 }
2003
2004 out:
2005 free(user);
2006 free(realm);
2007 free(pw);
2008 free(pw_mm);
2009 free(pps);
2010 free(cert_pem);
2011 free(fingerprint);
2012 return ret;
2013 }
2014
2015
hs20_spp_update_response(struct hs20_svc * ctx,xml_node_t * node,const char * user,const char * realm,const char * session_id,int dmacc)2016 static xml_node_t * hs20_spp_update_response(struct hs20_svc *ctx,
2017 xml_node_t *node,
2018 const char *user,
2019 const char *realm,
2020 const char *session_id,
2021 int dmacc)
2022 {
2023 char *status;
2024 xml_node_t *ret;
2025 char *val;
2026 enum hs20_session_operation oper;
2027
2028 status = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
2029 "sppStatus");
2030 if (status == NULL) {
2031 debug_print(ctx, 1, "No sppStatus attribute");
2032 return NULL;
2033 }
2034
2035 debug_print(ctx, 1, "sppUpdateResponse: sppStatus: %s sessionID: %s",
2036 status, session_id);
2037
2038 val = db_get_session_val(ctx, user, realm, session_id, "operation");
2039 if (!val) {
2040 debug_print(ctx, 1,
2041 "No session active for user: %s sessionID: %s",
2042 user, session_id);
2043 oper = NO_OPERATION;
2044 } else
2045 oper = atoi(val);
2046
2047 if (strcasecmp(status, "OK") == 0) {
2048 char *new_pw = NULL;
2049
2050 xml_node_get_attr_value_free(ctx->xml, status);
2051
2052 if (oper == USER_REMEDIATION) {
2053 new_pw = db_get_session_val(ctx, user, realm,
2054 session_id, "password");
2055 if (new_pw == NULL || strlen(new_pw) == 0) {
2056 free(new_pw);
2057 ret = build_spp_exchange_complete(
2058 ctx, session_id, "Error occurred",
2059 "Other");
2060 hs20_eventlog_node(ctx, user, realm,
2061 session_id, "No password "
2062 "had been assigned for "
2063 "session", ret);
2064 db_remove_session(ctx, user, realm, session_id);
2065 return ret;
2066 }
2067 oper = UPDATE_PASSWORD;
2068 }
2069 if (oper == UPDATE_PASSWORD) {
2070 if (!new_pw) {
2071 new_pw = db_get_session_val(ctx, user, realm,
2072 session_id,
2073 "password");
2074 if (!new_pw) {
2075 db_remove_session(ctx, user, realm,
2076 session_id);
2077 return NULL;
2078 }
2079 }
2080 debug_print(ctx, 1, "Update user '%s' password in DB",
2081 user);
2082 if (update_password(ctx, user, realm, new_pw, dmacc) <
2083 0) {
2084 debug_print(ctx, 1, "Failed to update user "
2085 "'%s' password in DB", user);
2086 ret = build_spp_exchange_complete(
2087 ctx, session_id, "Error occurred",
2088 "Other");
2089 hs20_eventlog_node(ctx, user, realm,
2090 session_id, "Failed to "
2091 "update database", ret);
2092 db_remove_session(ctx, user, realm, session_id);
2093 return ret;
2094 }
2095 hs20_eventlog(ctx, user, realm,
2096 session_id, "Updated user password "
2097 "in database", NULL);
2098 }
2099 if (oper == SUBSCRIPTION_REGISTRATION) {
2100 if (add_subscription(ctx, session_id) < 0) {
2101 debug_print(ctx, 1, "Failed to add "
2102 "subscription into DB");
2103 ret = build_spp_exchange_complete(
2104 ctx, session_id, "Error occurred",
2105 "Other");
2106 hs20_eventlog_node(ctx, user, realm,
2107 session_id, "Failed to "
2108 "update database", ret);
2109 db_remove_session(ctx, user, realm, session_id);
2110 return ret;
2111 }
2112 }
2113 if (oper == POLICY_REMEDIATION || oper == POLICY_UPDATE) {
2114 char *val;
2115 val = db_get_val(ctx, user, realm, "remediation",
2116 dmacc);
2117 if (val && strcmp(val, "policy") == 0)
2118 db_update_val(ctx, user, realm, "remediation",
2119 "", dmacc);
2120 free(val);
2121 }
2122 ret = build_spp_exchange_complete(
2123 ctx, session_id,
2124 "Exchange complete, release TLS connection", NULL);
2125 hs20_eventlog_node(ctx, user, realm, session_id,
2126 "Exchange completed", ret);
2127 db_remove_session(ctx, user, realm, session_id);
2128 return ret;
2129 }
2130
2131 ret = build_spp_exchange_complete(ctx, session_id, "Error occurred",
2132 "Other");
2133 hs20_eventlog_node(ctx, user, realm, session_id, "Error occurred", ret);
2134 db_remove_session(ctx, user, realm, session_id);
2135 xml_node_get_attr_value_free(ctx->xml, status);
2136 return ret;
2137 }
2138
2139
2140 #define SPP_SESSION_ID_LEN 16
2141
gen_spp_session_id(void)2142 static char * gen_spp_session_id(void)
2143 {
2144 FILE *f;
2145 int i;
2146 char *session;
2147
2148 session = os_malloc(SPP_SESSION_ID_LEN * 2 + 1);
2149 if (session == NULL)
2150 return NULL;
2151
2152 f = fopen("/dev/urandom", "r");
2153 if (f == NULL) {
2154 os_free(session);
2155 return NULL;
2156 }
2157 for (i = 0; i < SPP_SESSION_ID_LEN; i++)
2158 os_snprintf(session + i * 2, 3, "%02x", fgetc(f));
2159
2160 fclose(f);
2161 return session;
2162 }
2163
hs20_spp_server_process(struct hs20_svc * ctx,xml_node_t * node,const char * auth_user,const char * auth_realm,int dmacc)2164 xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node,
2165 const char *auth_user,
2166 const char *auth_realm, int dmacc)
2167 {
2168 xml_node_t *ret = NULL;
2169 char *session_id;
2170 const char *op_name;
2171 char *xml_err;
2172 char fname[200];
2173
2174 debug_dump_node(ctx, "received request", node);
2175
2176 if (!dmacc && auth_user && auth_realm) {
2177 char *real;
2178 real = db_get_val(ctx, auth_user, auth_realm, "identity", 0);
2179 if (!real) {
2180 real = db_get_val(ctx, auth_user, auth_realm,
2181 "identity", 1);
2182 if (real)
2183 dmacc = 1;
2184 }
2185 os_free(real);
2186 }
2187
2188 snprintf(fname, sizeof(fname), "%s/spp/spp.xsd", ctx->root_dir);
2189 if (xml_validate(ctx->xml, node, fname, &xml_err) < 0) {
2190 /*
2191 * We may not be able to extract the sessionID from invalid
2192 * input, but well, we can try.
2193 */
2194 session_id = xml_node_get_attr_value_ns(ctx->xml, node,
2195 SPP_NS_URI,
2196 "sessionID");
2197 debug_print(ctx, 1,
2198 "SPP message failed validation, xsd file: %s xml-error: %s",
2199 fname, xml_err);
2200 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2201 "SPP message failed validation", node);
2202 hs20_eventlog(ctx, auth_user, auth_realm, session_id,
2203 "Validation errors", xml_err);
2204 os_free(xml_err);
2205 xml_node_get_attr_value_free(ctx->xml, session_id);
2206 /* TODO: what to return here? */
2207 ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2208 "SppValidationError");
2209 return ret;
2210 }
2211
2212 session_id = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
2213 "sessionID");
2214 if (session_id) {
2215 char *tmp;
2216 debug_print(ctx, 1, "Received sessionID %s", session_id);
2217 tmp = os_strdup(session_id);
2218 xml_node_get_attr_value_free(ctx->xml, session_id);
2219 if (tmp == NULL)
2220 return NULL;
2221 session_id = tmp;
2222 } else {
2223 session_id = gen_spp_session_id();
2224 if (session_id == NULL) {
2225 debug_print(ctx, 1, "Failed to generate sessionID");
2226 return NULL;
2227 }
2228 debug_print(ctx, 1, "Generated sessionID %s", session_id);
2229 }
2230
2231 op_name = xml_node_get_localname(ctx->xml, node);
2232 if (op_name == NULL) {
2233 debug_print(ctx, 1, "Could not get op_name");
2234 return NULL;
2235 }
2236
2237 if (strcmp(op_name, "sppPostDevData") == 0) {
2238 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2239 "sppPostDevData received and validated",
2240 node);
2241 ret = hs20_spp_post_dev_data(ctx, node, auth_user, auth_realm,
2242 session_id, dmacc);
2243 } else if (strcmp(op_name, "sppUpdateResponse") == 0) {
2244 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2245 "sppUpdateResponse received and validated",
2246 node);
2247 ret = hs20_spp_update_response(ctx, node, auth_user,
2248 auth_realm, session_id, dmacc);
2249 } else {
2250 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2251 "Unsupported SPP message received and "
2252 "validated", node);
2253 debug_print(ctx, 1, "Unsupported operation '%s'", op_name);
2254 /* TODO: what to return here? */
2255 ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2256 "SppUnknownCommandError");
2257 }
2258 os_free(session_id);
2259
2260 if (ret == NULL) {
2261 /* TODO: what to return here? */
2262 ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2263 "SppInternalError");
2264 }
2265
2266 return ret;
2267 }
2268
2269
hs20_spp_server_init(struct hs20_svc * ctx)2270 int hs20_spp_server_init(struct hs20_svc *ctx)
2271 {
2272 char fname[200];
2273 ctx->db = NULL;
2274 snprintf(fname, sizeof(fname), "%s/AS/DB/eap_user.db", ctx->root_dir);
2275 if (sqlite3_open(fname, &ctx->db)) {
2276 printf("Failed to open sqlite database: %s\n",
2277 sqlite3_errmsg(ctx->db));
2278 sqlite3_close(ctx->db);
2279 return -1;
2280 }
2281
2282 return 0;
2283 }
2284
2285
hs20_spp_server_deinit(struct hs20_svc * ctx)2286 void hs20_spp_server_deinit(struct hs20_svc *ctx)
2287 {
2288 sqlite3_close(ctx->db);
2289 ctx->db = NULL;
2290 }
2291