2 * ws protocol handler plugin for "generic sessions"
4 * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation:
9 * version 2.1 of the License.
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.
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,
22 #include "private-lwsgs.h"
24 /* keep changes in sync with the enum in lwsgs.h */
25 static const char * const param_names[] = {
46 struct lwsgs_fill_args {
51 static const struct lws_protocols protocols[];
54 lwsgs_lookup_callback_email(void *priv, int cols, char **col_val,
57 struct lwsgs_fill_args *a = (struct lwsgs_fill_args *)priv;
60 for (n = 0; n < cols; n++) {
61 if (!strcmp(col_name[n], "content")) {
62 strncpy(a->buf, col_val[n], a->len - 1);
63 a->buf[a->len - 1] = '\0';
71 lwsgs_email_cb_get_body(struct lws_email *email, char *buf, int len)
73 struct per_vhost_data__gs *vhd = (struct per_vhost_data__gs *)email->data;
74 struct lwsgs_fill_args a;
75 char ss[150], esc[50];
80 lws_snprintf(ss, sizeof(ss) - 1,
81 "select content from email where username='%s';",
82 lws_sql_purify(esc, vhd->u.username, sizeof(esc) - 1));
84 strncpy(buf, "failed", len);
85 if (sqlite3_exec(vhd->pdb, ss, lwsgs_lookup_callback_email, &a,
87 lwsl_err("Unable to lookup email: %s\n",
88 sqlite3_errmsg(vhd->pdb));
97 lwsgs_email_cb_sent(struct lws_email *email)
99 struct per_vhost_data__gs *vhd = (struct per_vhost_data__gs *)email->data;
100 char s[200], esc[50];
102 /* mark the user as having sent the verification email */
103 lws_snprintf(s, sizeof(s) - 1,
104 "update users set verified=1 where username='%s' and verified==0;",
105 lws_sql_purify(esc, vhd->u.username, sizeof(esc) - 1));
106 if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
107 lwsl_err("%s: Unable to update user: %s\n", __func__,
108 sqlite3_errmsg(vhd->pdb));
112 lws_snprintf(s, sizeof(s) - 1,
113 "delete from email where username='%s';",
114 lws_sql_purify(esc, vhd->u.username, sizeof(esc) - 1));
115 if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
116 lwsl_err("%s: Unable to delete email text: %s\n", __func__,
117 sqlite3_errmsg(vhd->pdb));
125 lwsgs_email_cb_on_next(struct lws_email *email)
127 struct per_vhost_data__gs *vhd = lws_container_of(email,
128 struct per_vhost_data__gs, email);
129 char s[LWSGS_EMAIL_CONTENT_SIZE], esc[50];
130 time_t now = lws_now_secs();
133 * users not verified in 24h get deleted
135 lws_snprintf(s, sizeof(s) - 1, "delete from users where ((verified != %d)"
136 " and (creation_time <= %lu));", LWSGS_VERIFIED_ACCEPTED,
137 (unsigned long)now - vhd->timeout_email_secs);
138 if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
139 lwsl_err("Unable to expire users: %s\n",
140 sqlite3_errmsg(vhd->pdb));
144 lws_snprintf(s, sizeof(s) - 1, "update users set token_time=0 where "
145 "(token_time <= %lu);",
146 (unsigned long)now - vhd->timeout_email_secs);
147 if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
148 lwsl_err("Unable to expire users: %s\n",
149 sqlite3_errmsg(vhd->pdb));
153 vhd->u.username[0] = '\0';
154 lws_snprintf(s, sizeof(s) - 1, "select username from email limit 1;");
155 if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &vhd->u,
156 NULL) != SQLITE_OK) {
157 lwsl_err("Unable to lookup user: %s\n", sqlite3_errmsg(vhd->pdb));
161 lws_snprintf(s, sizeof(s) - 1,
162 "select username, creation_time, email, ip, verified, token"
163 " from users where username='%s' limit 1;",
164 lws_sql_purify(esc, vhd->u.username, sizeof(esc) - 1));
165 if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &vhd->u,
166 NULL) != SQLITE_OK) {
167 lwsl_err("Unable to lookup user: %s\n",
168 sqlite3_errmsg(vhd->pdb));
172 if (!vhd->u.username[0])
174 * nothing to do, we are idle and no suitable
175 * accounts waiting for verification. When a new user
176 * is added we will get kicked to try again.
180 strncpy(email->email_to, vhd->u.email, sizeof(email->email_to) - 1);
186 struct lwsgs_subst_args
188 struct per_session_data__gs *pss;
189 struct per_vhost_data__gs *vhd;
194 lwsgs_subst(void *data, int index)
196 struct lwsgs_subst_args *a = (struct lwsgs_subst_args *)data;
199 char esc[50], s[100];
202 a->pss->result[0] = '\0';
204 if (!lwsgs_get_sid_from_wsi(a->wsi, &sid)) {
205 if (lwsgs_lookup_session(a->vhd, &sid, a->pss->result, 31)) {
206 lwsl_notice("sid lookup for %s failed\n", sid.id);
207 a->pss->delete_session = sid;
210 lws_snprintf(s, sizeof(s) - 1, "select username,email "
211 "from users where username = '%s';",
212 lws_sql_purify(esc, a->pss->result, sizeof(esc) - 1));
213 if (sqlite3_exec(a->vhd->pdb, s, lwsgs_lookup_callback_user,
214 &u, NULL) != SQLITE_OK) {
215 lwsl_err("Unable to lookup token: %s\n",
216 sqlite3_errmsg(a->vhd->pdb));
217 a->pss->delete_session = sid;
221 lwsl_notice("no sid\n");
223 strncpy(a->pss->result + 32, u.email, 100);
227 return a->pss->result;
230 n = lwsgs_get_auth_level(a->vhd, a->pss->result);
231 sprintf(a->pss->result, "%d", n);
232 return a->pss->result;
234 return a->pss->result + 32;
241 callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
242 void *user, void *in, size_t len)
244 struct per_session_data__gs *pss = (struct per_session_data__gs *)user;
245 const struct lws_protocol_vhost_options *pvo;
246 struct per_vhost_data__gs *vhd = (struct per_vhost_data__gs *)
247 lws_protocol_vh_priv_get(lws_get_vhost(wsi),
249 char cookie[1024], username[32], *pc = cookie;
250 unsigned char buffer[LWS_PRE + LWSGS_EMAIL_CONTENT_SIZE];
251 struct lws_process_html_args *args;
252 struct lws_session_info *sinfo;
253 char s[LWSGS_EMAIL_CONTENT_SIZE];
254 unsigned char *p, *start, *end;
261 case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */
263 vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
264 &protocols[0], sizeof(struct per_vhost_data__gs));
267 vhd->context = lws_get_context(wsi);
270 vhd->timeout_idle_secs = 600;
271 vhd->timeout_absolute_secs = 36000;
272 vhd->timeout_anon_absolute_secs = 1200;
273 vhd->timeout_email_secs = 24 * 3600;
274 strcpy(vhd->email.email_helo, "unconfigured.com");
275 strcpy(vhd->email.email_from, "noreply@unconfigured.com");
276 strcpy(vhd->email_title, "Registration Email from unconfigured");
277 strcpy(vhd->email.email_smtp_ip, "127.0.0.1");
279 vhd->email.on_next = lwsgs_email_cb_on_next;
280 vhd->email.on_get_body = lwsgs_email_cb_get_body;
281 vhd->email.on_sent = lwsgs_email_cb_sent;
282 vhd->email.data = (void *)vhd;
284 pvo = (const struct lws_protocol_vhost_options *)in;
286 if (!strcmp(pvo->name, "admin-user"))
287 strncpy(vhd->admin_user, pvo->value,
288 sizeof(vhd->admin_user) - 1);
289 if (!strcmp(pvo->name, "admin-password-sha1"))
290 strncpy(vhd->admin_password_sha1.id, pvo->value,
291 sizeof(vhd->admin_password_sha1.id) - 1);
292 if (!strcmp(pvo->name, "session-db"))
293 strncpy(vhd->session_db, pvo->value,
294 sizeof(vhd->session_db) - 1);
295 if (!strcmp(pvo->name, "confounder"))
296 strncpy(vhd->confounder, pvo->value,
297 sizeof(vhd->confounder) - 1);
298 if (!strcmp(pvo->name, "email-from"))
299 strncpy(vhd->email.email_from, pvo->value,
300 sizeof(vhd->email.email_from) - 1);
301 if (!strcmp(pvo->name, "email-helo"))
302 strncpy(vhd->email.email_helo, pvo->value,
303 sizeof(vhd->email.email_helo) - 1);
304 if (!strcmp(pvo->name, "email-template"))
305 strncpy(vhd->email_template, pvo->value,
306 sizeof(vhd->email_template) - 1);
307 if (!strcmp(pvo->name, "email-title"))
308 strncpy(vhd->email_title, pvo->value,
309 sizeof(vhd->email_title) - 1);
310 if (!strcmp(pvo->name, "email-contact-person"))
311 strncpy(vhd->email_contact_person, pvo->value,
312 sizeof(vhd->email_contact_person) - 1);
313 if (!strcmp(pvo->name, "email-confirm-url-base"))
314 strncpy(vhd->email_confirm_url, pvo->value,
315 sizeof(vhd->email_confirm_url) - 1);
316 if (!strcmp(pvo->name, "email-server-ip"))
317 strncpy(vhd->email.email_smtp_ip, pvo->value,
318 sizeof(vhd->email.email_smtp_ip) - 1);
320 if (!strcmp(pvo->name, "timeout-idle-secs"))
321 vhd->timeout_idle_secs = atoi(pvo->value);
322 if (!strcmp(pvo->name, "timeout-absolute-secs"))
323 vhd->timeout_absolute_secs = atoi(pvo->value);
324 if (!strcmp(pvo->name, "timeout-anon-absolute-secs"))
325 vhd->timeout_anon_absolute_secs = atoi(pvo->value);
326 if (!strcmp(pvo->name, "email-expire"))
327 vhd->timeout_email_secs = atoi(pvo->value);
330 if (!vhd->admin_user[0] ||
331 !vhd->admin_password_sha1.id[0] ||
332 !vhd->session_db[0]) {
333 lwsl_err("generic-sessions: "
334 "You must give \"admin-user\", "
335 "\"admin-password-sha1\", "
336 "and \"session_db\" per-vhost options\n");
340 if (sqlite3_open_v2(vhd->session_db, &vhd->pdb,
341 SQLITE_OPEN_READWRITE |
342 SQLITE_OPEN_CREATE, NULL) != SQLITE_OK) {
343 lwsl_err("Unable to open session db %s: %s\n",
344 vhd->session_db, sqlite3_errmsg(vhd->pdb));
349 if (sqlite3_prepare(vhd->pdb,
350 "create table if not exists sessions ("
352 " username varchar(32),"
355 -1, &sm, NULL) != SQLITE_OK) {
356 lwsl_err("Unable to prepare session table init: %s\n",
357 sqlite3_errmsg(vhd->pdb));
362 if (sqlite3_step(sm) != SQLITE_DONE) {
363 lwsl_err("Unable to run session table init: %s\n",
364 sqlite3_errmsg(vhd->pdb));
368 sqlite3_finalize(sm);
370 if (sqlite3_exec(vhd->pdb,
371 "create table if not exists users ("
372 " username varchar(32),"
373 " creation_time integer,"
375 " email varchar(100),"
376 " pwhash varchar(42),"
377 " pwsalt varchar(42),"
378 " pwchange_time integer,"
379 " token varchar(42),"
381 " token_time integer,"
382 " last_forgot_validated integer,"
383 " primary key (username)"
385 NULL, NULL, NULL) != SQLITE_OK) {
386 lwsl_err("Unable to create user table: %s\n",
387 sqlite3_errmsg(vhd->pdb));
392 sprintf(s, "create table if not exists email ("
393 " username varchar(32),"
395 " primary key (username)"
397 if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
398 lwsl_err("Unable to create user table: %s\n",
399 sqlite3_errmsg(vhd->pdb));
404 lws_email_init(&vhd->email, lws_uv_getloop(vhd->context, 0),
405 LWSGS_EMAIL_CONTENT_SIZE);
407 vhd->email_inited = 1;
410 case LWS_CALLBACK_PROTOCOL_DESTROY:
411 // lwsl_notice("gs: LWS_CALLBACK_PROTOCOL_DESTROY: v=%p, ctx=%p\n", vhd, vhd->context);
413 sqlite3_close(vhd->pdb);
416 if (vhd->email_inited) {
417 lws_email_destroy(&vhd->email);
418 vhd->email_inited = 0;
422 case LWS_CALLBACK_HTTP:
423 lwsl_info("LWS_CALLBACK_HTTP: %s\n", (const char *)in);
425 pss->login_session.id[0] = '\0';
427 strncpy(pss->onward, (char *)in, sizeof(pss->onward) - 1);
428 pss->onward[sizeof(pss->onward) - 1] = '\0';
430 if (!strcmp((const char *)in, "/lwsgs-forgot")) {
431 lwsgs_handler_forgot(vhd, wsi, pss);
432 goto redirect_with_cookie;
435 if (!strcmp((const char *)in, "/lwsgs-confirm")) {
436 lwsgs_handler_confirm(vhd, wsi, pss);
437 goto redirect_with_cookie;
439 if (!strcmp((const char *)in, "/lwsgs-check")) {
440 lwsgs_handler_check(vhd, wsi, pss);
444 if (!strcmp((const char *)in, "/lwsgs-login"))
446 if (!strcmp((const char *)in, "/lwsgs-logout"))
448 if (!strcmp((const char *)in, "/lwsgs-forgot"))
450 if (!strcmp((const char *)in, "/lwsgs-change"))
453 /* if no legitimate url for GET, return 404 */
455 lwsl_err("http doing 404 on %s\n", (const char *)in);
456 lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
459 case LWS_CALLBACK_CHECK_ACCESS_RIGHTS:
463 args = (struct lws_process_html_args *)in;
464 lwsl_debug("LWS_CALLBACK_CHECK_ACCESS_RIGHTS\n");
465 if (!lwsgs_get_sid_from_wsi(wsi, &sid)) {
466 if (lwsgs_lookup_session(vhd, &sid, username, sizeof(username))) {
467 static const char * const oprot[] = {
468 "http://", "https://"
470 lwsl_notice("session lookup for %s failed, probably expired\n", sid.id);
471 pss->delete_session = sid;
472 args->final = 1; /* signal we dealt with it */
473 if (lws_hdr_copy(wsi, cookie, sizeof(cookie) - 1,
476 lws_snprintf(pss->onward, sizeof(pss->onward) - 1,
477 "%s%s%s", oprot[!!lws_is_ssl(wsi)],
479 lwsl_notice("redirecting to ourselves with cookie refresh\n");
480 /* we need a redirect to ourselves, session cookie is expired */
481 goto redirect_with_cookie;
484 lwsl_notice("failed to get sid from wsi\n");
486 n = lwsgs_get_auth_level(vhd, username);
488 if ((args->max_len & n) != args->max_len) {
489 lwsl_notice("Access rights fail 0x%X vs 0x%X (cookie %s)\n",
490 args->max_len, n, sid.id);
493 lwsl_debug("Access rights OK\n");
496 case LWS_CALLBACK_SESSION_INFO:
499 sinfo = (struct lws_session_info *)in;
500 sinfo->username[0] = '\0';
501 sinfo->email[0] = '\0';
503 sinfo->session[0] = '\0';
507 lwsl_debug("LWS_CALLBACK_SESSION_INFO\n");
508 if (lwsgs_get_sid_from_wsi(wsi, &sid))
510 if (lwsgs_lookup_session(vhd, &sid, username, sizeof(username)))
513 lws_snprintf(s, sizeof(s) - 1,
514 "select username, email from users where username='%s';",
516 if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
518 lwsl_err("Unable to lookup token: %s\n",
519 sqlite3_errmsg(vhd->pdb));
522 strncpy(sinfo->username, u.username, sizeof(sinfo->username) - 1);
523 sinfo->username[sizeof(sinfo->username) - 1] = '\0';
524 strncpy(sinfo->email, u.email, sizeof(sinfo->email) - 1);
525 strncpy(sinfo->session, sid.id, sizeof(sinfo->session) - 1);
526 sinfo->mask = lwsgs_get_auth_level(vhd, username);
527 lws_get_peer_simple(wsi, sinfo->ip, sizeof(sinfo->ip));
532 case LWS_CALLBACK_PROCESS_HTML:
534 args = (struct lws_process_html_args *)in;
536 static const char * const vars[] = {
541 struct lwsgs_subst_args a;
547 pss->phs.vars = vars;
548 pss->phs.count_vars = ARRAY_SIZE(vars);
549 pss->phs.replace = lwsgs_subst;
552 if (lws_chunked_html_process(args, &pss->phs))
557 case LWS_CALLBACK_HTTP_BODY:
562 pss->spa = lws_spa_create(wsi, param_names,
563 ARRAY_SIZE(param_names), 1024,
569 if (lws_spa_process(pss->spa, in, len)) {
570 lwsl_notice("spa process blew\n");
575 case LWS_CALLBACK_HTTP_BODY_COMPLETION:
580 lwsl_info("LWS_CALLBACK_HTTP_BODY_COMPLETION: %s\n", pss->onward);
581 lws_spa_finalize(pss->spa);
583 if (!strcmp((char *)pss->onward, "/lwsgs-change")) {
584 if (!lwsgs_handler_change_password(vhd, wsi, pss)) {
585 cp = lws_spa_get_string(pss->spa, FGS_GOOD);
589 cp = lws_spa_get_string(pss->spa, FGS_BAD);
590 lwsl_notice("user/password no good %s\n",
591 lws_spa_get_string(pss->spa, FGS_USERNAME));
592 strncpy(pss->onward, cp, sizeof(pss->onward) - 1);
593 pss->onward[sizeof(pss->onward) - 1] = '\0';
594 goto completion_flow;
597 if (!strcmp((char *)pss->onward, "/lwsgs-login")) {
598 if (lws_spa_get_string(pss->spa, FGS_FORGOT) &&
599 lws_spa_get_string(pss->spa, FGS_FORGOT)[0]) {
600 if (lwsgs_handler_forgot_pw_form(vhd, wsi, pss)) {
604 /* get the email monitor to take a look */
605 lws_email_check(&vhd->email);
610 if (!lws_spa_get_string(pss->spa, FGS_USERNAME) ||
611 !lws_spa_get_string(pss->spa, FGS_PASSWORD)) {
612 lwsl_notice("username '%s' or pw '%s' missing\n",
613 lws_spa_get_string(pss->spa, FGS_USERNAME),
614 lws_spa_get_string(pss->spa, FGS_PASSWORD));
618 if (lws_spa_get_string(pss->spa, FGS_REGISTER) &&
619 lws_spa_get_string(pss->spa, FGS_REGISTER)[0]) {
621 if (lwsgs_handler_register_form(vhd, wsi, pss))
626 /* get the email monitor to take a look */
627 lws_email_check(&vhd->email);
630 strncpy(pss->onward, lws_spa_get_string(pss->spa, n),
631 sizeof(pss->onward) - 1);
632 pss->onward[sizeof(pss->onward) - 1] = '\0';
633 pss->login_expires = 0;
634 pss->logging_out = 1;
635 goto completion_flow;
638 /* we have the username and password... check if admin */
639 if (lwsgw_check_admin(vhd, lws_spa_get_string(pss->spa, FGS_USERNAME),
640 lws_spa_get_string(pss->spa, FGS_PASSWORD))) {
641 if (lws_spa_get_string(pss->spa, FGS_ADMIN))
642 cp = lws_spa_get_string(pss->spa, FGS_ADMIN);
644 if (lws_spa_get_string(pss->spa, FGS_GOOD))
645 cp = lws_spa_get_string(pss->spa, FGS_GOOD);
647 lwsl_info("No admin or good target url in form\n");
650 lwsl_debug("admin\n");
654 /* check users in database */
656 if (!lwsgs_check_credentials(vhd, lws_spa_get_string(pss->spa, FGS_USERNAME),
657 lws_spa_get_string(pss->spa, FGS_PASSWORD))) {
658 lwsl_info("pw hash check met\n");
659 cp = lws_spa_get_string(pss->spa, FGS_GOOD);
662 lwsl_notice("user/password no good %s\n",
663 lws_spa_get_string(pss->spa, FGS_USERNAME));
665 if (!lws_spa_get_string(pss->spa, FGS_BAD)) {
666 lwsl_info("No admin or good target url in form\n");
670 strncpy(pss->onward, lws_spa_get_string(pss->spa, FGS_BAD),
671 sizeof(pss->onward) - 1);
672 pss->onward[sizeof(pss->onward) - 1] = '\0';
673 lwsl_debug("failed\n");
675 goto completion_flow;
678 if (!strcmp((char *)pss->onward, "/lwsgs-logout")) {
680 lwsl_notice("/logout\n");
682 if (lwsgs_get_sid_from_wsi(wsi, &pss->login_session)) {
683 lwsl_notice("not logged in...\n");
687 lwsgw_update_session(vhd, &pss->login_session, "");
689 if (!lws_spa_get_string(pss->spa, FGS_GOOD)) {
690 lwsl_info("No admin or good target url in form\n");
694 strncpy(pss->onward, lws_spa_get_string(pss->spa, FGS_GOOD), sizeof(pss->onward) - 1);
695 pss->onward[sizeof(pss->onward) - 1] = '\0';
697 pss->login_expires = 0;
698 pss->logging_out = 1;
700 goto completion_flow;
706 strncpy(pss->onward, cp, sizeof(pss->onward) - 1);
707 pss->onward[sizeof(pss->onward) - 1] = '\0';
709 if (lwsgs_get_sid_from_wsi(wsi, &sid))
712 pss->login_expires = lws_now_secs() +
713 vhd->timeout_absolute_secs;
716 /* we need to create a new, authorized session */
718 if (lwsgs_new_session_id(vhd, &pss->login_session,
719 lws_spa_get_string(pss->spa, FGS_USERNAME),
723 lwsl_info("Creating new session: %s\n",
724 pss->login_session.id);
727 * we can just update the existing session to be
730 lwsl_info("Authorizing existing session %s", sid.id);
731 lwsgw_update_session(vhd, &sid,
732 lws_spa_get_string(pss->spa, FGS_USERNAME));
733 pss->login_session = sid;
737 lwsgw_expire_old_sessions(vhd);
738 goto redirect_with_cookie;
740 case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
741 if (pss && pss->spa) {
742 lws_spa_destroy(pss->spa);
747 case LWS_CALLBACK_ADD_HEADERS:
748 lwsgw_expire_old_sessions(vhd);
750 args = (struct lws_process_html_args *)in;
752 if (pss->delete_session.id[0]) {
754 lwsgw_cookie_from_session(&pss->delete_session, 0, &pc,
755 cookie + sizeof(cookie) - 1);
757 lwsl_info("deleting cookie '%s'\n", cookie);
759 if (lws_add_http_header_by_name(wsi,
760 (unsigned char *)"set-cookie:",
761 (unsigned char *)cookie, pc - cookie,
762 (unsigned char **)&args->p,
763 (unsigned char *)args->p + args->max_len))
767 if (!pss->login_session.id[0])
768 lwsgs_get_sid_from_wsi(wsi, &pss->login_session);
770 if (!pss->login_session.id[0] && !pss->logging_out) {
772 pss->login_expires = lws_now_secs() +
773 vhd->timeout_anon_absolute_secs;
774 if (lwsgs_new_session_id(vhd, &pss->login_session, "",
778 lwsgw_cookie_from_session(&pss->login_session,
779 pss->login_expires, &pc,
780 cookie + sizeof(cookie) - 1);
782 lwsl_info("LWS_CALLBACK_ADD_HEADERS: setting cookie '%s'\n", cookie);
783 if (lws_add_http_header_by_name(wsi,
784 (unsigned char *)"set-cookie:",
785 (unsigned char *)cookie, pc - cookie,
786 (unsigned char **)&args->p,
787 (unsigned char *)args->p + args->max_len))
798 redirect_with_cookie:
799 p = buffer + LWS_PRE;
801 end = p + sizeof(buffer) - LWS_PRE;
803 if (lws_add_http_header_status(wsi, HTTP_STATUS_SEE_OTHER, &p, end))
806 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_LOCATION,
807 (unsigned char *)pss->onward,
808 strlen(pss->onward), &p, end))
811 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
812 (unsigned char *)"text/html", 9, &p, end))
814 if (lws_add_http_header_content_length(wsi, 0, &p, end))
817 if (pss->delete_session.id[0]) {
818 lwsgw_cookie_from_session(&pss->delete_session, 0, &pc,
819 cookie + sizeof(cookie) - 1);
821 lwsl_notice("deleting cookie '%s'\n", cookie);
823 if (lws_add_http_header_by_name(wsi,
824 (unsigned char *)"set-cookie:",
825 (unsigned char *)cookie, pc - cookie,
830 if (!pss->login_session.id[0]) {
831 pss->login_expires = lws_now_secs() +
832 vhd->timeout_anon_absolute_secs;
833 if (lwsgs_new_session_id(vhd, &pss->login_session, "",
837 pss->login_expires = lws_now_secs() +
838 vhd->timeout_absolute_secs;
840 if (pss->login_session.id[0] || pss->logging_out) {
842 * we succeeded to login, we must issue a login
843 * cookie with the prepared data
847 lwsgw_cookie_from_session(&pss->login_session,
848 pss->login_expires, &pc,
849 cookie + sizeof(cookie) - 1);
851 lwsl_info("setting cookie '%s'\n", cookie);
853 pss->logging_out = 0;
855 if (lws_add_http_header_by_name(wsi,
856 (unsigned char *)"set-cookie:",
857 (unsigned char *)cookie, pc - cookie,
862 if (lws_finalize_http_header(wsi, &p, end))
865 n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
872 if (lws_http_transaction_completed(wsi))
878 static const struct lws_protocols protocols[] = {
880 "protocol-generic-sessions",
881 callback_generic_sessions,
882 sizeof(struct per_session_data__gs),
887 LWS_EXTERN LWS_VISIBLE int
888 init_protocol_generic_sessions(struct lws_context *context,
889 struct lws_plugin_capability *c)
891 if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
892 lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
897 c->protocols = protocols;
898 c->count_protocols = ARRAY_SIZE(protocols);
899 c->extensions = NULL;
900 c->count_extensions = 0;
905 LWS_EXTERN LWS_VISIBLE int
906 destroy_protocol_generic_sessions(struct lws_context *context)