f450a1934ec2061b99f7e23f10d1e6d9da6c7128
[platform/upstream/libwebsockets.git] / plugins / generic-sessions / handlers.c
1 /*
2  * ws protocol handler plugin for "generic sessions"
3  *
4  * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public
8  * License as published by the Free Software Foundation:
9  * version 2.1 of the License.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA  02110-1301  USA
20  */
21
22 #include "private-lwsgs.h"
23
24 /* handle account confirmation links */
25
26 int
27 lwsgs_handler_confirm(struct per_vhost_data__gs *vhd, struct lws *wsi,
28                       struct per_session_data__gs *pss)
29 {
30         char cookie[1024], s[256], esc[50];
31         struct lws_gs_event_args a;
32         struct lwsgs_user u;
33
34         if (lws_hdr_copy_fragment(wsi, cookie, sizeof(cookie),
35                                   WSI_TOKEN_HTTP_URI_ARGS, 0) < 0)
36                 goto verf_fail;
37
38         if (strncmp(cookie, "token=", 6))
39                 goto verf_fail;
40
41         u.username[0] = '\0';
42         lws_snprintf(s, sizeof(s) - 1,
43                  "select username,email,verified from users where token = '%s';",
44                  lws_sql_purify(esc, &cookie[6], sizeof(esc) - 1));
45         if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
46             SQLITE_OK) {
47                 lwsl_err("Unable to lookup token: %s\n",
48                          sqlite3_errmsg(vhd->pdb));
49                 goto verf_fail;
50         }
51
52         if (!u.username[0] || u.verified != 1) {
53                 lwsl_notice("verify token doesn't map to unverified user\n");
54                 goto verf_fail;
55         }
56
57         lwsl_notice("Verifying %s\n", u.username);
58         lws_snprintf(s, sizeof(s) - 1,
59                  "update users set verified=%d where username='%s';",
60                  LWSGS_VERIFIED_ACCEPTED,
61                  lws_sql_purify(esc, u.username, sizeof(esc) - 1));
62         if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
63             SQLITE_OK) {
64                 lwsl_err("Unable to lookup token: %s\n",
65                          sqlite3_errmsg(vhd->pdb));
66
67                 goto verf_fail;
68         }
69
70         lwsl_notice("deleting account\n");
71
72         a.event = LWSGSE_CREATED;
73         a.username = u.username;
74         a.email = u.email;
75         lws_callback_vhost_protocols(wsi, LWS_CALLBACK_GS_EVENT, &a, 0);
76
77         lws_snprintf(pss->onward, sizeof(pss->onward),
78                  "%s/post-verify-ok.html", vhd->email_confirm_url);
79
80         pss->login_expires = lws_now_secs() + vhd->timeout_absolute_secs;
81
82         pss->delete_session.id[0] = '\0';
83         lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
84
85         /* we need to create a new, authorized session */
86
87         if (lwsgs_new_session_id(vhd, &pss->login_session, u.username,
88                                  pss->login_expires))
89                 goto verf_fail;
90
91         lwsl_notice("Creating new session: %s, redir to %s\n",
92                     pss->login_session.id, pss->onward);
93
94         return 0;
95
96 verf_fail:
97         pss->delete_session.id[0] = '\0';
98         lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
99         pss->login_expires = 0;
100
101         lws_snprintf(pss->onward, sizeof(pss->onward), "%s/post-verify-fail.html",
102                  vhd->email_confirm_url);
103
104         return 1;
105 }
106
107 /* handle forgot password confirmation links */
108
109 int
110 lwsgs_handler_forgot(struct per_vhost_data__gs *vhd, struct lws *wsi,
111                      struct per_session_data__gs *pss)
112 {
113         char cookie[1024], s[256], esc[50];
114         struct lwsgs_user u;
115         const char *a;
116
117         a = lws_get_urlarg_by_name(wsi, "token=", cookie, sizeof(cookie));
118         if (!a)
119                 goto forgot_fail;
120
121         u.username[0] = '\0';
122         lws_snprintf(s, sizeof(s) - 1,
123                  "select username,verified from users where verified=%d and "
124                  "token = '%s' and token_time != 0;",
125                  LWSGS_VERIFIED_ACCEPTED,
126                  lws_sql_purify(esc, &cookie[6], sizeof(esc) - 1));
127         if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
128             SQLITE_OK) {
129                 lwsl_err("Unable to lookup token: %s\n",
130                          sqlite3_errmsg(vhd->pdb));
131
132                 goto forgot_fail;
133         }
134
135         if (!u.username[0]) {
136                 puts(s);
137                 lwsl_notice("forgot token doesn't map to verified user\n");
138                 goto forgot_fail;
139         }
140
141         /* mark user as having validated forgot flow just now */
142
143         lws_snprintf(s, sizeof(s) - 1,
144                  "update users set token_time=0,last_forgot_validated=%lu "
145                  "where username='%s';",
146                  (unsigned long)lws_now_secs(),
147                  lws_sql_purify(esc, u.username, sizeof(esc) - 1));
148
149         if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
150             SQLITE_OK) {
151                 lwsl_err("Unable to lookup token: %s\n",
152                          sqlite3_errmsg(vhd->pdb));
153                 goto forgot_fail;
154         }
155
156         a = lws_get_urlarg_by_name(wsi, "good=", cookie, sizeof(cookie));
157         if (!a)
158                 a = "broken-forget-post-good-url";
159
160         lws_snprintf(pss->onward, sizeof(pss->onward),
161                  "%s/%s", vhd->email_confirm_url, a);
162
163         pss->login_expires = lws_now_secs() + vhd->timeout_absolute_secs;
164
165         pss->delete_session.id[0] = '\0';
166         lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
167
168         /* we need to create a new, authorized session */
169         if (lwsgs_new_session_id(vhd, &pss->login_session,
170                                  u.username,
171                                  pss->login_expires))
172                 goto forgot_fail;
173
174         lwsl_notice("Creating new session: %s, redir to %s\n",
175                     pss->login_session.id, pss->onward);
176
177         return 0;
178
179 forgot_fail:
180         pss->delete_session.id[0] = '\0';
181         lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
182         pss->login_expires = 0;
183
184         a = lws_get_urlarg_by_name(wsi, "bad=", cookie, sizeof(cookie));
185         if (!a)
186                 a = "broken-forget-post-bad-url";
187
188         lws_snprintf(pss->onward, sizeof(pss->onward), "%s/%s",
189                  vhd->email_confirm_url, a);
190
191         return 1;
192 }
193
194 /* support dynamic username / email checking */
195
196 int
197 lwsgs_handler_check(struct per_vhost_data__gs *vhd,
198                     struct lws *wsi, struct per_session_data__gs *pss)
199 {
200         static const char * const colname[] = { "username", "email" };
201         char cookie[1024], s[256], esc[50], *pc;
202         unsigned char *p, *start, *end, buffer[LWS_PRE + 256];
203         struct lwsgs_user u;
204         int n;
205
206         /*
207          * either /check?email=xxx@yyy   or: /check?username=xxx
208          * returns '0' if not already registered, else '1'
209          */
210
211         u.username[0] = '\0';
212         if (lws_hdr_copy_fragment(wsi, cookie, sizeof(cookie),
213                                   WSI_TOKEN_HTTP_URI_ARGS, 0) < 0)
214                 goto reply;
215
216         n = !strncmp(cookie, "email=", 6);
217         pc = strchr(cookie, '=');
218         if (!pc) {
219                 lwsl_notice("cookie has no =\n");
220                 goto reply;
221         }
222         pc++;
223
224         /* admin user cannot be registered in user db */
225         if (!strcmp(vhd->admin_user, pc)) {
226                 u.username[0] = 'a';
227                 goto reply;
228         }
229
230         lws_snprintf(s, sizeof(s) - 1,
231                  "select username, email from users where %s = '%s';",
232                  colname[n], lws_sql_purify(esc, pc, sizeof(esc) - 1));
233         if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
234             SQLITE_OK) {
235                 lwsl_err("Unable to lookup token: %s\n",
236                          sqlite3_errmsg(vhd->pdb));
237                 goto reply;
238         }
239
240 reply:
241         s[0] = '0' + !!u.username[0];
242         p = buffer + LWS_PRE;
243         start = p;
244         end = p + sizeof(buffer) - LWS_PRE;
245
246         if (lws_add_http_header_status(wsi, 200, &p, end))
247                 return -1;
248         if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
249                                          (unsigned char *)"text/plain", 10,
250                                          &p, end))
251                 return -1;
252
253         if (lws_add_http_header_content_length(wsi, 1, &p, end))
254                 return -1;
255
256         if (lws_finalize_http_header(wsi, &p, end))
257                 return -1;
258
259         n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
260         if (n != (p - start)) {
261                 lwsl_err("_write returned %d from %ld\n", n, (long)(p - start));
262                 return -1;
263         }
264         n = lws_write(wsi, (unsigned char *)s, 1, LWS_WRITE_HTTP);
265         if (n != 1)
266                 return -1;
267
268         return 0;
269 }
270
271 /* handle forgot password confirmation links */
272
273 int
274 lwsgs_handler_change_password(struct per_vhost_data__gs *vhd, struct lws *wsi,
275                               struct per_session_data__gs *pss)
276 {
277         char s[256], esc[50], username[50];
278         struct lwsgs_user u;
279         lwsgw_hash sid;
280         int n = 0;
281
282         /* see if he's logged in */
283         username[0] = '\0';
284         if (!lwsgs_get_sid_from_wsi(wsi, &sid)) {
285                 u.username[0] = '\0';
286                 if (!lwsgs_lookup_session(vhd, &sid, username, sizeof(username))) {
287                         n = 1; /* yes, logged in */
288                         if (lwsgs_lookup_user(vhd, username, &u))
289                                 return 1;
290
291                         /* did a forgot pw ? */
292                         if (u.last_forgot_validated > lws_now_secs() - 300) {
293                                 n |= LWSGS_AUTH_FORGOT_FLOW;
294                                 lwsl_debug("within forgot password flow\n");
295                         }
296                 }
297         }
298
299         lwsl_debug("auth value %d\n", n);
300
301         /* if he just did forgot pw flow, don't need old pw */
302         if ((n & (LWSGS_AUTH_FORGOT_FLOW | 1)) != (LWSGS_AUTH_FORGOT_FLOW | 1)) {
303                 /* otherwise user:pass must be right */
304                 lwsl_debug("checking pw\n");
305                 if (lwsgs_check_credentials(vhd,
306                            lws_spa_get_string(pss->spa, FGS_USERNAME),
307                            lws_spa_get_string(pss->spa, FGS_CURPW))) {
308                         lwsl_notice("credentials bad\n");
309                         return 1;
310                 }
311
312                 lwsl_debug("current pw checks out\n");
313
314                 strncpy(u.username, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(u.username) - 1);
315                 u.username[sizeof(u.username) - 1] = '\0';
316         }
317
318         /* does he want to delete his account? */
319
320         if (lws_spa_get_length(pss->spa, FGS_DELETE)) {
321                 struct lws_gs_event_args a;
322
323                 lwsl_notice("deleting account\n");
324
325                 a.event = LWSGSE_DELETED;
326                 a.username = u.username;
327                 a.email = "";
328                 lws_callback_vhost_protocols(wsi, LWS_CALLBACK_GS_EVENT, &a, 0);
329
330                 lws_snprintf(s, sizeof(s) - 1,
331                          "delete from users where username='%s';"
332                          "delete from sessions where username='%s';",
333                          lws_sql_purify(esc, u.username, sizeof(esc) - 1),
334                          lws_sql_purify(esc, u.username, sizeof(esc) - 1));
335                 goto sql;
336         }
337
338         if (lwsgs_hash_password(vhd, lws_spa_get_string(pss->spa, FGS_PASSWORD), &u))
339                 return 1;
340
341         lwsl_notice("updating password hash\n");
342
343         lws_snprintf(s, sizeof(s) - 1,
344                  "update users set pwhash='%s', pwsalt='%s', "
345                  "last_forgot_validated=0 where username='%s';",
346                  u.pwhash.id, u.pwsalt.id,
347                  lws_sql_purify(esc, u.username, sizeof(esc) - 1));
348
349 sql:
350         if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
351                 lwsl_err("Unable to update pw hash: %s\n",
352                          sqlite3_errmsg(vhd->pdb));
353                 return 1;
354         }
355
356         return 0;
357 }
358
359 int
360 lwsgs_handler_forgot_pw_form(struct per_vhost_data__gs *vhd,
361                              struct lws *wsi,
362                              struct per_session_data__gs *pss)
363 {
364         char s[LWSGS_EMAIL_CONTENT_SIZE];
365         unsigned char buffer[LWS_PRE + LWSGS_EMAIL_CONTENT_SIZE];
366         char esc[50], esc1[50], esc2[50], esc3[50], esc4[50];
367         struct lwsgs_user u;
368         lwsgw_hash hash;
369         unsigned char sid_rand[20];
370         int n;
371
372         lwsl_notice("FORGOT %s %s\n",
373                     lws_spa_get_string(pss->spa, FGS_USERNAME),
374                     lws_spa_get_string(pss->spa, FGS_EMAIL));
375
376         if (!lws_spa_get_string(pss->spa, FGS_USERNAME) &&
377             !lws_spa_get_string(pss->spa, FGS_EMAIL)) {
378                 lwsl_err("Form must provide either "
379                           "username or email\n");
380                 return -1;
381         }
382
383         if (!lws_spa_get_string(pss->spa, FGS_FORGOT_GOOD) ||
384             !lws_spa_get_string(pss->spa, FGS_FORGOT_BAD) ||
385             !lws_spa_get_string(pss->spa, FGS_FORGOT_POST_GOOD) ||
386             !lws_spa_get_string(pss->spa, FGS_FORGOT_POST_BAD)) {
387                 lwsl_err("Form must provide reg-good "
388                           "and reg-bad (and post-*)"
389                           "targets\n");
390                 return -1;
391         }
392
393         u.username[0] = '\0';
394         if (lws_spa_get_string(pss->spa, FGS_USERNAME))
395                 lws_snprintf(s, sizeof(s) - 1,
396                  "select username,email "
397                  "from users where username = '%s';",
398                  lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_USERNAME),
399                                  sizeof(esc) - 1));
400         else
401                 lws_snprintf(s, sizeof(s) - 1,
402                  "select username,email "
403                  "from users where email = '%s';",
404                  lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_EMAIL), sizeof(esc) - 1));
405         if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
406             SQLITE_OK) {
407                 lwsl_err("Unable to lookup token: %s\n",
408                          sqlite3_errmsg(vhd->pdb));
409                 return 1;
410         }
411         if (!u.username[0]) {
412                 lwsl_err("No match found %s\n", s);
413                 return 1;
414         }
415
416         lws_get_peer_simple(wsi, pss->ip, sizeof(pss->ip));
417         if (lws_get_random(vhd->context, sid_rand,
418                            sizeof(sid_rand)) !=
419                            sizeof(sid_rand)) {
420                 lwsl_err("Problem getting random for token\n");
421                 return 1;
422         }
423         sha1_to_lwsgw_hash(sid_rand, &hash);
424         n = lws_snprintf(s, sizeof(s),
425                 "From: Forgot Password Assistant Noreply <%s>\n"
426                 "To: %s <%s>\n"
427                   "Subject: Password reset request\n"
428                   "\n"
429                   "Hello, %s\n\n"
430                   "We received a password reset request from IP %s for this email,\n"
431                   "to confirm you want to do that, please click the link below.\n\n",
432                 lws_sql_purify(esc, vhd->email.email_from, sizeof(esc) - 1),
433                 lws_sql_purify(esc1, u.username, sizeof(esc1) - 1),
434                 lws_sql_purify(esc2, u.email, sizeof(esc2) - 1),
435                 lws_sql_purify(esc3, u.username, sizeof(esc3) - 1),
436                 lws_sql_purify(esc4, pss->ip, sizeof(esc4) - 1));
437         lws_snprintf(s + n, sizeof(s) -n,
438                   "%s/lwsgs-forgot?token=%s"
439                    "&good=%s"
440                    "&bad=%s\n\n"
441                   "If this request is unexpected, please ignore it and\n"
442                   "no further action will be taken.\n\n"
443                 "If you have any questions or concerns about this\n"
444                 "automated email, you can contact a real person at\n"
445                 "%s.\n"
446                 "\n.\n",
447                 vhd->email_confirm_url, hash.id,
448                 lws_urlencode(esc1,
449                              lws_spa_get_string(pss->spa, FGS_FORGOT_POST_GOOD),
450                              sizeof(esc1) - 1),
451                 lws_urlencode(esc3,
452                               lws_spa_get_string(pss->spa, FGS_FORGOT_POST_BAD),
453                               sizeof(esc3) - 1),
454                 vhd->email_contact_person);
455
456         lws_snprintf((char *)buffer, sizeof(buffer) - 1,
457                  "insert into email(username, content)"
458                  " values ('%s', '%s');",
459                 lws_sql_purify(esc, u.username, sizeof(esc) - 1), s);
460         if (sqlite3_exec(vhd->pdb, (char *)buffer, NULL,
461                          NULL, NULL) != SQLITE_OK) {
462                 lwsl_err("Unable to insert email: %s\n",
463                          sqlite3_errmsg(vhd->pdb));
464                 return 1;
465         }
466
467         lws_snprintf(s, sizeof(s) - 1,
468                  "update users set token='%s',token_time='%ld' where username='%s';",
469                  hash.id, (long)lws_now_secs(),
470                  lws_sql_purify(esc, u.username, sizeof(esc) - 1));
471         if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) !=
472             SQLITE_OK) {
473                 lwsl_err("Unable to set token: %s\n",
474                          sqlite3_errmsg(vhd->pdb));
475                 return 1;
476         }
477
478         return 0;
479 }
480
481 int
482 lwsgs_handler_register_form(struct per_vhost_data__gs *vhd,
483                              struct lws *wsi,
484                              struct per_session_data__gs *pss)
485 {
486         unsigned char buffer[LWS_PRE + LWSGS_EMAIL_CONTENT_SIZE];
487         char esc[50], esc1[50], esc2[50], esc3[50], esc4[50];
488         char s[LWSGS_EMAIL_CONTENT_SIZE];
489         unsigned char sid_rand[20];
490         struct lwsgs_user u;
491         lwsgw_hash hash;
492
493         lwsl_notice("REGISTER %s %s %s\n",
494                         lws_spa_get_string(pss->spa, FGS_USERNAME),
495                         lws_spa_get_string(pss->spa, FGS_PASSWORD),
496                         lws_spa_get_string(pss->spa, FGS_EMAIL));
497         if (lwsgs_get_sid_from_wsi(wsi,
498             &pss->login_session))
499                 return 1;
500
501         lws_get_peer_simple(wsi, pss->ip, sizeof(pss->ip));
502         lwsl_notice("IP=%s\n", pss->ip);
503
504         if (!lws_spa_get_string(pss->spa, FGS_REG_GOOD) ||
505             !lws_spa_get_string(pss->spa, FGS_REG_BAD)) {
506                 lwsl_info("Form must provide reg-good and reg-bad targets\n");
507                 return -1;
508         }
509
510         /* admin user cannot be registered in user db */
511         if (!strcmp(vhd->admin_user,
512                     lws_spa_get_string(pss->spa, FGS_USERNAME)))
513                 return 1;
514
515         if (!lwsgs_lookup_user(vhd,
516                         lws_spa_get_string(pss->spa, FGS_USERNAME), &u)) {
517                 lwsl_notice("user %s already registered\n",
518                             lws_spa_get_string(pss->spa, FGS_USERNAME));
519                 return 1;
520         }
521
522         u.username[0] = '\0';
523         lws_snprintf(s, sizeof(s) - 1, "select username, email from users where email = '%s';",
524                  lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_EMAIL),
525                  sizeof(esc) - 1));
526
527         if (sqlite3_exec(vhd->pdb, s,
528                          lwsgs_lookup_callback_user, &u, NULL) != SQLITE_OK) {
529                 lwsl_err("Unable to lookup token: %s\n",
530                          sqlite3_errmsg(vhd->pdb));
531                 return 1;
532         }
533
534         if (u.username[0]) {
535                 lwsl_notice("email %s already in use\n",
536                             lws_spa_get_string(pss->spa, FGS_USERNAME));
537                 return 1;
538         }
539
540         if (lwsgs_hash_password(vhd, lws_spa_get_string(pss->spa, FGS_PASSWORD),
541                                 &u)) {
542                 lwsl_err("Password hash failed\n");
543                 return 1;
544         }
545
546         if (lws_get_random(vhd->context, sid_rand, sizeof(sid_rand)) !=
547             sizeof(sid_rand)) {
548                 lwsl_err("Problem getting random for token\n");
549                 return 1;
550         }
551         sha1_to_lwsgw_hash(sid_rand, &hash);
552
553         lws_snprintf((char *)buffer, sizeof(buffer) - 1,
554                  "insert into users(username,"
555                  " creation_time, ip, email, verified,"
556                  " pwhash, pwsalt, token, last_forgot_validated)"
557                  " values ('%s', %lu, '%s', '%s', 0,"
558                  " '%s', '%s', '%s', 0);",
559                 lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(esc) - 1),
560                 (unsigned long)lws_now_secs(),
561                 lws_sql_purify(esc1, pss->ip, sizeof(esc1) - 1),
562                 lws_sql_purify(esc2, lws_spa_get_string(pss->spa, FGS_EMAIL), sizeof(esc2) - 1),
563                 u.pwhash.id, u.pwsalt.id, hash.id);
564
565         if (sqlite3_exec(vhd->pdb, (char *)buffer, NULL, NULL, NULL) != SQLITE_OK) {
566                 lwsl_err("Unable to insert user: %s\n",
567                          sqlite3_errmsg(vhd->pdb));
568                 return 1;
569         }
570
571         lws_snprintf(s, sizeof(s),
572                 "From: Noreply <%s>\n"
573                 "To: %s <%s>\n"
574                   "Subject: Registration verification\n"
575                   "\n"
576                   "Hello, %s\n\n"
577                   "We received a registration from IP %s using this email,\n"
578                   "to confirm it is legitimate, please click the link below.\n\n"
579                   "%s/lwsgs-confirm?token=%s\n\n"
580                   "If this request is unexpected, please ignore it and\n"
581                   "no further action will be taken.\n\n"
582                 "If you have any questions or concerns about this\n"
583                 "automated email, you can contact a real person at\n"
584                 "%s.\n"
585                 "\n.\n",
586                 lws_sql_purify(esc, vhd->email.email_from, sizeof(esc) - 1),
587                 lws_sql_purify(esc1, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(esc1) - 1),
588                 lws_sql_purify(esc2, lws_spa_get_string(pss->spa, FGS_EMAIL), sizeof(esc2) - 1),
589                 lws_sql_purify(esc3, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(esc3) - 1),
590                 lws_sql_purify(esc4, pss->ip, sizeof(esc4) - 1),
591                 vhd->email_confirm_url, hash.id,
592                 vhd->email_contact_person);
593
594         lws_snprintf((char *)buffer, sizeof(buffer) - 1,
595                  "insert into email(username, content) values ('%s', '%s');",
596                 lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_USERNAME),
597                                sizeof(esc) - 1), s);
598
599         if (sqlite3_exec(vhd->pdb, (char *)buffer, NULL, NULL, NULL) != SQLITE_OK) {
600                 lwsl_err("Unable to insert email: %s\n",
601                          sqlite3_errmsg(vhd->pdb));
602                 return 1;
603         }
604
605         return 0;
606 }