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 if (devinfo)
1827 db_add_session_devinfo(ctx, session_id, devinfo);
1828 if (devdetail)
1829 db_add_session_devdetail(ctx, session_id, devdetail);
1830 ret = hs20_user_input_complete(ctx, user, realm, dmacc,
1831 session_id);
1832 hs20_eventlog_node(ctx, user, realm, session_id,
1833 "user input completed response", ret);
1834 goto out;
1835 }
1836
1837 if (strcasecmp(req_reason, "Certificate enrollment completed") == 0) {
1838 ret = hs20_cert_enroll_completed(ctx, user, realm, dmacc,
1839 session_id);
1840 hs20_eventlog_node(ctx, user, realm, session_id,
1841 "certificate enrollment response", ret);
1842 goto out;
1843 }
1844
1845 if (strcasecmp(req_reason, "Certificate enrollment failed") == 0) {
1846 ret = hs20_cert_enroll_failed(ctx, user, realm, dmacc,
1847 session_id);
1848 hs20_eventlog_node(ctx, user, realm, session_id,
1849 "certificate enrollment failed response",
1850 ret);
1851 goto out;
1852 }
1853
1854 debug_print(ctx, 1, "Unsupported requestReason '%s' user '%s'",
1855 req_reason, user);
1856 out:
1857 xml_node_get_attr_value_free(ctx->xml, req_reason_buf);
1858 xml_node_get_attr_value_free(ctx->xml, redirect_uri);
1859 if (devinfo)
1860 xml_node_free(ctx->xml, devinfo);
1861 if (devdetail)
1862 xml_node_free(ctx->xml, devdetail);
1863 return ret;
1864 }
1865
1866
build_spp_exchange_complete(struct hs20_svc * ctx,const char * session_id,const char * status,const char * error_code)1867 static xml_node_t * build_spp_exchange_complete(struct hs20_svc *ctx,
1868 const char *session_id,
1869 const char *status,
1870 const char *error_code)
1871 {
1872 xml_namespace_t *ns;
1873 xml_node_t *spp_node, *node;
1874
1875 spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
1876 "sppExchangeComplete");
1877
1878
1879 xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
1880 xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
1881 xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
1882
1883 if (error_code) {
1884 node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
1885 xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
1886 error_code);
1887 }
1888
1889 return spp_node;
1890 }
1891
1892
add_subscription(struct hs20_svc * ctx,const char * session_id)1893 static int add_subscription(struct hs20_svc *ctx, const char *session_id)
1894 {
1895 char *user, *realm, *pw, *pw_mm, *pps, *str;
1896 char *sql;
1897 int ret = -1;
1898 char *free_account;
1899 int free_acc;
1900 char *type;
1901 int cert = 0;
1902 char *cert_pem, *fingerprint;
1903
1904 user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
1905 realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
1906 pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
1907 pw_mm = db_get_session_val(ctx, NULL, NULL, session_id,
1908 "machine_managed");
1909 pps = db_get_session_val(ctx, NULL, NULL, session_id, "pps");
1910 cert_pem = db_get_session_val(ctx, NULL, NULL, session_id, "cert_pem");
1911 fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
1912 type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
1913 if (type && strcmp(type, "cert") == 0)
1914 cert = 1;
1915 free(type);
1916
1917 if (!user || !realm || !pw) {
1918 debug_print(ctx, 1, "Could not find session info from DB for "
1919 "the new subscription");
1920 goto out;
1921 }
1922
1923 free_account = db_get_osu_config_val(ctx, realm, "free_account");
1924 free_acc = free_account && strcmp(free_account, user) == 0;
1925 free(free_account);
1926
1927 debug_print(ctx, 1,
1928 "New subscription: user='%s' realm='%s' free_acc=%d",
1929 user, realm, free_acc);
1930 debug_print(ctx, 1, "New subscription: pps='%s'", pps);
1931
1932 sql = sqlite3_mprintf("UPDATE eventlog SET user=%Q, realm=%Q WHERE "
1933 "sessionid=%Q AND (user='' OR user IS NULL)",
1934 user, realm, session_id);
1935 if (sql) {
1936 debug_print(ctx, 1, "DB: %s", sql);
1937 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
1938 debug_print(ctx, 1, "Failed to update eventlog in "
1939 "sqlite database: %s",
1940 sqlite3_errmsg(ctx->db));
1941 }
1942 sqlite3_free(sql);
1943 }
1944
1945 if (free_acc) {
1946 hs20_eventlog(ctx, user, realm, session_id,
1947 "completed shared free account registration",
1948 NULL);
1949 ret = 0;
1950 goto out;
1951 }
1952
1953 sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,"
1954 "methods,cert,cert_pem,machine_managed) VALUES "
1955 "(%Q,%Q,1,%Q,%Q,%Q,%d)",
1956 user, realm, cert ? "TLS" : "TTLS-MSCHAPV2",
1957 fingerprint ? fingerprint : "",
1958 cert_pem ? cert_pem : "",
1959 pw_mm && atoi(pw_mm) ? 1 : 0);
1960 if (sql == NULL)
1961 goto out;
1962 debug_print(ctx, 1, "DB: %s", sql);
1963 if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
1964 debug_print(ctx, 1, "Failed to add user in sqlite database: %s",
1965 sqlite3_errmsg(ctx->db));
1966 sqlite3_free(sql);
1967 goto out;
1968 }
1969 sqlite3_free(sql);
1970
1971 if (cert)
1972 ret = 0;
1973 else
1974 ret = update_password(ctx, user, realm, pw, 0);
1975 if (ret < 0) {
1976 sql = sqlite3_mprintf("DELETE FROM users WHERE identity=%Q AND "
1977 "realm=%Q AND phase2=1",
1978 user, realm);
1979 if (sql) {
1980 debug_print(ctx, 1, "DB: %s", sql);
1981 sqlite3_exec(ctx->db, sql, NULL, NULL, NULL);
1982 sqlite3_free(sql);
1983 }
1984 }
1985
1986 if (pps)
1987 db_update_mo_str(ctx, user, realm, "pps", pps);
1988
1989 str = db_get_session_val(ctx, NULL, NULL, session_id, "devinfo");
1990 if (str) {
1991 db_update_mo_str(ctx, user, realm, "devinfo", str);
1992 free(str);
1993 }
1994
1995 str = db_get_session_val(ctx, NULL, NULL, session_id, "devdetail");
1996 if (str) {
1997 db_update_mo_str(ctx, user, realm, "devdetail", str);
1998 free(str);
1999 }
2000
2001 if (ret == 0) {
2002 hs20_eventlog(ctx, user, realm, session_id,
2003 "completed subscription registration", NULL);
2004 }
2005
2006 out:
2007 free(user);
2008 free(realm);
2009 free(pw);
2010 free(pw_mm);
2011 free(pps);
2012 free(cert_pem);
2013 free(fingerprint);
2014 return ret;
2015 }
2016
2017
hs20_spp_update_response(struct hs20_svc * ctx,xml_node_t * node,const char * user,const char * realm,const char * session_id,int dmacc)2018 static xml_node_t * hs20_spp_update_response(struct hs20_svc *ctx,
2019 xml_node_t *node,
2020 const char *user,
2021 const char *realm,
2022 const char *session_id,
2023 int dmacc)
2024 {
2025 char *status;
2026 xml_node_t *ret;
2027 char *val;
2028 enum hs20_session_operation oper;
2029
2030 status = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
2031 "sppStatus");
2032 if (status == NULL) {
2033 debug_print(ctx, 1, "No sppStatus attribute");
2034 return NULL;
2035 }
2036
2037 debug_print(ctx, 1, "sppUpdateResponse: sppStatus: %s sessionID: %s",
2038 status, session_id);
2039
2040 val = db_get_session_val(ctx, user, realm, session_id, "operation");
2041 if (!val) {
2042 debug_print(ctx, 1,
2043 "No session active for user: %s sessionID: %s",
2044 user, session_id);
2045 oper = NO_OPERATION;
2046 } else
2047 oper = atoi(val);
2048
2049 if (strcasecmp(status, "OK") == 0) {
2050 char *new_pw = NULL;
2051
2052 xml_node_get_attr_value_free(ctx->xml, status);
2053
2054 if (oper == USER_REMEDIATION) {
2055 new_pw = db_get_session_val(ctx, user, realm,
2056 session_id, "password");
2057 if (new_pw == NULL || strlen(new_pw) == 0) {
2058 free(new_pw);
2059 ret = build_spp_exchange_complete(
2060 ctx, session_id, "Error occurred",
2061 "Other");
2062 hs20_eventlog_node(ctx, user, realm,
2063 session_id, "No password "
2064 "had been assigned for "
2065 "session", ret);
2066 db_remove_session(ctx, user, realm, session_id);
2067 return ret;
2068 }
2069 oper = UPDATE_PASSWORD;
2070 }
2071 if (oper == UPDATE_PASSWORD) {
2072 if (!new_pw) {
2073 new_pw = db_get_session_val(ctx, user, realm,
2074 session_id,
2075 "password");
2076 if (!new_pw) {
2077 db_remove_session(ctx, user, realm,
2078 session_id);
2079 return NULL;
2080 }
2081 }
2082 debug_print(ctx, 1, "Update user '%s' password in DB",
2083 user);
2084 if (update_password(ctx, user, realm, new_pw, dmacc) <
2085 0) {
2086 debug_print(ctx, 1, "Failed to update user "
2087 "'%s' password in DB", user);
2088 ret = build_spp_exchange_complete(
2089 ctx, session_id, "Error occurred",
2090 "Other");
2091 hs20_eventlog_node(ctx, user, realm,
2092 session_id, "Failed to "
2093 "update database", ret);
2094 db_remove_session(ctx, user, realm, session_id);
2095 return ret;
2096 }
2097 hs20_eventlog(ctx, user, realm,
2098 session_id, "Updated user password "
2099 "in database", NULL);
2100 }
2101 if (oper == SUBSCRIPTION_REGISTRATION) {
2102 if (add_subscription(ctx, session_id) < 0) {
2103 debug_print(ctx, 1, "Failed to add "
2104 "subscription into DB");
2105 ret = build_spp_exchange_complete(
2106 ctx, session_id, "Error occurred",
2107 "Other");
2108 hs20_eventlog_node(ctx, user, realm,
2109 session_id, "Failed to "
2110 "update database", ret);
2111 db_remove_session(ctx, user, realm, session_id);
2112 return ret;
2113 }
2114 }
2115 if (oper == POLICY_REMEDIATION || oper == POLICY_UPDATE) {
2116 char *val;
2117 val = db_get_val(ctx, user, realm, "remediation",
2118 dmacc);
2119 if (val && strcmp(val, "policy") == 0)
2120 db_update_val(ctx, user, realm, "remediation",
2121 "", dmacc);
2122 free(val);
2123 }
2124 ret = build_spp_exchange_complete(
2125 ctx, session_id,
2126 "Exchange complete, release TLS connection", NULL);
2127 hs20_eventlog_node(ctx, user, realm, session_id,
2128 "Exchange completed", ret);
2129 db_remove_session(ctx, user, realm, session_id);
2130 return ret;
2131 }
2132
2133 ret = build_spp_exchange_complete(ctx, session_id, "Error occurred",
2134 "Other");
2135 hs20_eventlog_node(ctx, user, realm, session_id, "Error occurred", ret);
2136 db_remove_session(ctx, user, realm, session_id);
2137 xml_node_get_attr_value_free(ctx->xml, status);
2138 return ret;
2139 }
2140
2141
2142 #define SPP_SESSION_ID_LEN 16
2143
gen_spp_session_id(void)2144 static char * gen_spp_session_id(void)
2145 {
2146 FILE *f;
2147 int i;
2148 char *session;
2149
2150 session = os_malloc(SPP_SESSION_ID_LEN * 2 + 1);
2151 if (session == NULL)
2152 return NULL;
2153
2154 f = fopen("/dev/urandom", "r");
2155 if (f == NULL) {
2156 os_free(session);
2157 return NULL;
2158 }
2159 for (i = 0; i < SPP_SESSION_ID_LEN; i++)
2160 os_snprintf(session + i * 2, 3, "%02x", fgetc(f));
2161
2162 fclose(f);
2163 return session;
2164 }
2165
hs20_spp_server_process(struct hs20_svc * ctx,xml_node_t * node,const char * auth_user,const char * auth_realm,int dmacc)2166 xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node,
2167 const char *auth_user,
2168 const char *auth_realm, int dmacc)
2169 {
2170 xml_node_t *ret = NULL;
2171 char *session_id;
2172 const char *op_name;
2173 char *xml_err;
2174 char fname[200];
2175
2176 debug_dump_node(ctx, "received request", node);
2177
2178 if (!dmacc && auth_user && auth_realm) {
2179 char *real;
2180 real = db_get_val(ctx, auth_user, auth_realm, "identity", 0);
2181 if (!real) {
2182 real = db_get_val(ctx, auth_user, auth_realm,
2183 "identity", 1);
2184 if (real)
2185 dmacc = 1;
2186 }
2187 os_free(real);
2188 }
2189
2190 snprintf(fname, sizeof(fname), "%s/spp/spp.xsd", ctx->root_dir);
2191 if (xml_validate(ctx->xml, node, fname, &xml_err) < 0) {
2192 /*
2193 * We may not be able to extract the sessionID from invalid
2194 * input, but well, we can try.
2195 */
2196 session_id = xml_node_get_attr_value_ns(ctx->xml, node,
2197 SPP_NS_URI,
2198 "sessionID");
2199 debug_print(ctx, 1,
2200 "SPP message failed validation, xsd file: %s xml-error: %s",
2201 fname, xml_err);
2202 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2203 "SPP message failed validation", node);
2204 hs20_eventlog(ctx, auth_user, auth_realm, session_id,
2205 "Validation errors", xml_err);
2206 os_free(xml_err);
2207 xml_node_get_attr_value_free(ctx->xml, session_id);
2208 /* TODO: what to return here? */
2209 ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2210 "SppValidationError");
2211 return ret;
2212 }
2213
2214 session_id = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
2215 "sessionID");
2216 if (session_id) {
2217 char *tmp;
2218 debug_print(ctx, 1, "Received sessionID %s", session_id);
2219 tmp = os_strdup(session_id);
2220 xml_node_get_attr_value_free(ctx->xml, session_id);
2221 if (tmp == NULL)
2222 return NULL;
2223 session_id = tmp;
2224 } else {
2225 session_id = gen_spp_session_id();
2226 if (session_id == NULL) {
2227 debug_print(ctx, 1, "Failed to generate sessionID");
2228 return NULL;
2229 }
2230 debug_print(ctx, 1, "Generated sessionID %s", session_id);
2231 }
2232
2233 op_name = xml_node_get_localname(ctx->xml, node);
2234 if (op_name == NULL) {
2235 debug_print(ctx, 1, "Could not get op_name");
2236 return NULL;
2237 }
2238
2239 if (strcmp(op_name, "sppPostDevData") == 0) {
2240 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2241 "sppPostDevData received and validated",
2242 node);
2243 ret = hs20_spp_post_dev_data(ctx, node, auth_user, auth_realm,
2244 session_id, dmacc);
2245 } else if (strcmp(op_name, "sppUpdateResponse") == 0) {
2246 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2247 "sppUpdateResponse received and validated",
2248 node);
2249 ret = hs20_spp_update_response(ctx, node, auth_user,
2250 auth_realm, session_id, dmacc);
2251 } else {
2252 hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
2253 "Unsupported SPP message received and "
2254 "validated", node);
2255 debug_print(ctx, 1, "Unsupported operation '%s'", op_name);
2256 /* TODO: what to return here? */
2257 ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2258 "SppUnknownCommandError");
2259 }
2260 os_free(session_id);
2261
2262 if (ret == NULL) {
2263 /* TODO: what to return here? */
2264 ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
2265 "SppInternalError");
2266 }
2267
2268 return ret;
2269 }
2270
2271
hs20_spp_server_init(struct hs20_svc * ctx)2272 int hs20_spp_server_init(struct hs20_svc *ctx)
2273 {
2274 char fname[200];
2275 ctx->db = NULL;
2276 snprintf(fname, sizeof(fname), "%s/AS/DB/eap_user.db", ctx->root_dir);
2277 if (sqlite3_open(fname, &ctx->db)) {
2278 printf("Failed to open sqlite database: %s\n",
2279 sqlite3_errmsg(ctx->db));
2280 sqlite3_close(ctx->db);
2281 return -1;
2282 }
2283
2284 return 0;
2285 }
2286
2287
hs20_spp_server_deinit(struct hs20_svc * ctx)2288 void hs20_spp_server_deinit(struct hs20_svc *ctx)
2289 {
2290 sqlite3_close(ctx->db);
2291 ctx->db = NULL;
2292 }
2293