Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / hs20 / server / spp_server.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
2288 void hs20_spp_server_deinit(struct hs20_svc *ctx)
2289 {
2290         sqlite3_close(ctx->db);
2291         ctx->db = NULL;
2292 }