blob: 67e0683649781f4d25d639f381650b5ba0256533 [file] [log] [blame]
/*
* ws protocol handler plugin for "generic sessions"
*
* Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "private-lwsgs.h"
/* keep changes in sync with the enum in lwsgs.h */
static const char * const param_names[] = {
"username",
"password",
"password2",
"email",
"register",
"good",
"bad",
"reg-good",
"reg-bad",
"admin",
"forgot",
"forgot-good",
"forgot-bad",
"forgot-post-good",
"forgot-post-bad",
"change",
"curpw",
"delete"
};
struct lwsgs_fill_args {
char *buf;
int len;
};
static const struct lws_protocols protocols[];
static int
lwsgs_lookup_callback_email(void *priv, int cols, char **col_val,
char **col_name)
{
struct lwsgs_fill_args *a = (struct lwsgs_fill_args *)priv;
int n;
for (n = 0; n < cols; n++) {
if (!strcmp(col_name[n], "content")) {
strncpy(a->buf, col_val[n], a->len - 1);
a->buf[a->len - 1] = '\0';
continue;
}
}
return 0;
}
static int
lwsgs_email_cb_get_body(struct lws_email *email, char *buf, int len)
{
struct per_vhost_data__gs *vhd = (struct per_vhost_data__gs *)email->data;
struct lwsgs_fill_args a;
char ss[150], esc[50];
a.buf = buf;
a.len = len;
lws_snprintf(ss, sizeof(ss) - 1,
"select content from email where username='%s';",
lws_sql_purify(esc, vhd->u.username, sizeof(esc) - 1));
strncpy(buf, "failed", len);
if (sqlite3_exec(vhd->pdb, ss, lwsgs_lookup_callback_email, &a,
NULL) != SQLITE_OK) {
lwsl_err("Unable to lookup email: %s\n",
sqlite3_errmsg(vhd->pdb));
return 1;
}
return 0;
}
static int
lwsgs_email_cb_sent(struct lws_email *email)
{
struct per_vhost_data__gs *vhd = (struct per_vhost_data__gs *)email->data;
char s[200], esc[50];
/* mark the user as having sent the verification email */
lws_snprintf(s, sizeof(s) - 1,
"update users set verified=1 where username='%s' and verified==0;",
lws_sql_purify(esc, vhd->u.username, sizeof(esc) - 1));
if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
lwsl_err("%s: Unable to update user: %s\n", __func__,
sqlite3_errmsg(vhd->pdb));
return 1;
}
lws_snprintf(s, sizeof(s) - 1,
"delete from email where username='%s';",
lws_sql_purify(esc, vhd->u.username, sizeof(esc) - 1));
if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
lwsl_err("%s: Unable to delete email text: %s\n", __func__,
sqlite3_errmsg(vhd->pdb));
return 1;
}
return 0;
}
static int
lwsgs_email_cb_on_next(struct lws_email *email)
{
struct per_vhost_data__gs *vhd = lws_container_of(email,
struct per_vhost_data__gs, email);
char s[LWSGS_EMAIL_CONTENT_SIZE], esc[50];
time_t now = lws_now_secs();
/*
* users not verified in 24h get deleted
*/
lws_snprintf(s, sizeof(s) - 1, "delete from users where ((verified != %d)"
" and (creation_time <= %lu));", LWSGS_VERIFIED_ACCEPTED,
(unsigned long)now - vhd->timeout_email_secs);
if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
lwsl_err("Unable to expire users: %s\n",
sqlite3_errmsg(vhd->pdb));
return 1;
}
lws_snprintf(s, sizeof(s) - 1, "update users set token_time=0 where "
"(token_time <= %lu);",
(unsigned long)now - vhd->timeout_email_secs);
if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
lwsl_err("Unable to expire users: %s\n",
sqlite3_errmsg(vhd->pdb));
return 1;
}
vhd->u.username[0] = '\0';
lws_snprintf(s, sizeof(s) - 1, "select username from email limit 1;");
if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &vhd->u,
NULL) != SQLITE_OK) {
lwsl_err("Unable to lookup user: %s\n", sqlite3_errmsg(vhd->pdb));
return 1;
}
lws_snprintf(s, sizeof(s) - 1,
"select username, creation_time, email, ip, verified, token"
" from users where username='%s' limit 1;",
lws_sql_purify(esc, vhd->u.username, sizeof(esc) - 1));
if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &vhd->u,
NULL) != SQLITE_OK) {
lwsl_err("Unable to lookup user: %s\n",
sqlite3_errmsg(vhd->pdb));
return 1;
}
if (!vhd->u.username[0])
/*
* nothing to do, we are idle and no suitable
* accounts waiting for verification. When a new user
* is added we will get kicked to try again.
*/
return 1;
strncpy(email->email_to, vhd->u.email, sizeof(email->email_to) - 1);
return 0;
}
struct lwsgs_subst_args
{
struct per_session_data__gs *pss;
struct per_vhost_data__gs *vhd;
struct lws *wsi;
};
static const char *
lwsgs_subst(void *data, int index)
{
struct lwsgs_subst_args *a = (struct lwsgs_subst_args *)data;
struct lwsgs_user u;
lwsgw_hash sid;
char esc[50], s[100];
int n;
a->pss->result[0] = '\0';
u.email[0] = '\0';
if (!lwsgs_get_sid_from_wsi(a->wsi, &sid)) {
if (lwsgs_lookup_session(a->vhd, &sid, a->pss->result, 31)) {
lwsl_notice("sid lookup for %s failed\n", sid.id);
a->pss->delete_session = sid;
return NULL;
}
lws_snprintf(s, sizeof(s) - 1, "select username,email "
"from users where username = '%s';",
lws_sql_purify(esc, a->pss->result, sizeof(esc) - 1));
if (sqlite3_exec(a->vhd->pdb, s, lwsgs_lookup_callback_user,
&u, NULL) != SQLITE_OK) {
lwsl_err("Unable to lookup token: %s\n",
sqlite3_errmsg(a->vhd->pdb));
a->pss->delete_session = sid;
return NULL;
}
} else
lwsl_notice("no sid\n");
strncpy(a->pss->result + 32, u.email, 100);
switch (index) {
case 0:
return a->pss->result;
case 1:
n = lwsgs_get_auth_level(a->vhd, a->pss->result);
sprintf(a->pss->result, "%d", n);
return a->pss->result;
case 2:
return a->pss->result + 32;
}
return NULL;
}
static int
callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
struct per_session_data__gs *pss = (struct per_session_data__gs *)user;
const struct lws_protocol_vhost_options *pvo;
struct per_vhost_data__gs *vhd = (struct per_vhost_data__gs *)
lws_protocol_vh_priv_get(lws_get_vhost(wsi),
&protocols[0]);
char cookie[1024], username[32], *pc = cookie;
unsigned char buffer[LWS_PRE + LWSGS_EMAIL_CONTENT_SIZE];
struct lws_process_html_args *args;
struct lws_session_info *sinfo;
char s[LWSGS_EMAIL_CONTENT_SIZE];
unsigned char *p, *start, *end;
sqlite3_stmt *sm;
lwsgw_hash sid;
const char *cp;
int n;
switch (reason) {
case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */
vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
&protocols[0], sizeof(struct per_vhost_data__gs));
if (!vhd)
return 1;
vhd->context = lws_get_context(wsi);
/* defaults */
vhd->timeout_idle_secs = 600;
vhd->timeout_absolute_secs = 36000;
vhd->timeout_anon_absolute_secs = 1200;
vhd->timeout_email_secs = 24 * 3600;
strcpy(vhd->email.email_helo, "unconfigured.com");
strcpy(vhd->email.email_from, "noreply@unconfigured.com");
strcpy(vhd->email_title, "Registration Email from unconfigured");
strcpy(vhd->email.email_smtp_ip, "127.0.0.1");
vhd->email.on_next = lwsgs_email_cb_on_next;
vhd->email.on_get_body = lwsgs_email_cb_get_body;
vhd->email.on_sent = lwsgs_email_cb_sent;
vhd->email.data = (void *)vhd;
pvo = (const struct lws_protocol_vhost_options *)in;
while (pvo) {
if (!strcmp(pvo->name, "admin-user"))
strncpy(vhd->admin_user, pvo->value,
sizeof(vhd->admin_user) - 1);
if (!strcmp(pvo->name, "admin-password-sha1"))
strncpy(vhd->admin_password_sha1.id, pvo->value,
sizeof(vhd->admin_password_sha1.id) - 1);
if (!strcmp(pvo->name, "session-db"))
strncpy(vhd->session_db, pvo->value,
sizeof(vhd->session_db) - 1);
if (!strcmp(pvo->name, "confounder"))
strncpy(vhd->confounder, pvo->value,
sizeof(vhd->confounder) - 1);
if (!strcmp(pvo->name, "email-from"))
strncpy(vhd->email.email_from, pvo->value,
sizeof(vhd->email.email_from) - 1);
if (!strcmp(pvo->name, "email-helo"))
strncpy(vhd->email.email_helo, pvo->value,
sizeof(vhd->email.email_helo) - 1);
if (!strcmp(pvo->name, "email-template"))
strncpy(vhd->email_template, pvo->value,
sizeof(vhd->email_template) - 1);
if (!strcmp(pvo->name, "email-title"))
strncpy(vhd->email_title, pvo->value,
sizeof(vhd->email_title) - 1);
if (!strcmp(pvo->name, "email-contact-person"))
strncpy(vhd->email_contact_person, pvo->value,
sizeof(vhd->email_contact_person) - 1);
if (!strcmp(pvo->name, "email-confirm-url-base"))
strncpy(vhd->email_confirm_url, pvo->value,
sizeof(vhd->email_confirm_url) - 1);
if (!strcmp(pvo->name, "email-server-ip"))
strncpy(vhd->email.email_smtp_ip, pvo->value,
sizeof(vhd->email.email_smtp_ip) - 1);
if (!strcmp(pvo->name, "timeout-idle-secs"))
vhd->timeout_idle_secs = atoi(pvo->value);
if (!strcmp(pvo->name, "timeout-absolute-secs"))
vhd->timeout_absolute_secs = atoi(pvo->value);
if (!strcmp(pvo->name, "timeout-anon-absolute-secs"))
vhd->timeout_anon_absolute_secs = atoi(pvo->value);
if (!strcmp(pvo->name, "email-expire"))
vhd->timeout_email_secs = atoi(pvo->value);
pvo = pvo->next;
}
if (!vhd->admin_user[0] ||
!vhd->admin_password_sha1.id[0] ||
!vhd->session_db[0]) {
lwsl_err("generic-sessions: "
"You must give \"admin-user\", "
"\"admin-password-sha1\", "
"and \"session_db\" per-vhost options\n");
return 1;
}
if (sqlite3_open_v2(vhd->session_db, &vhd->pdb,
SQLITE_OPEN_READWRITE |
SQLITE_OPEN_CREATE, NULL) != SQLITE_OK) {
lwsl_err("Unable to open session db %s: %s\n",
vhd->session_db, sqlite3_errmsg(vhd->pdb));
return 1;
}
if (sqlite3_prepare(vhd->pdb,
"create table if not exists sessions ("
" name char(40),"
" username varchar(32),"
" expire integer"
");",
-1, &sm, NULL) != SQLITE_OK) {
lwsl_err("Unable to prepare session table init: %s\n",
sqlite3_errmsg(vhd->pdb));
return 1;
}
if (sqlite3_step(sm) != SQLITE_DONE) {
lwsl_err("Unable to run session table init: %s\n",
sqlite3_errmsg(vhd->pdb));
return 1;
}
sqlite3_finalize(sm);
if (sqlite3_exec(vhd->pdb,
"create table if not exists users ("
" username varchar(32),"
" creation_time integer,"
" ip varchar(46),"
" email varchar(100),"
" pwhash varchar(42),"
" pwsalt varchar(42),"
" pwchange_time integer,"
" token varchar(42),"
" verified integer,"
" token_time integer,"
" last_forgot_validated integer,"
" primary key (username)"
");",
NULL, NULL, NULL) != SQLITE_OK) {
lwsl_err("Unable to create user table: %s\n",
sqlite3_errmsg(vhd->pdb));
return 1;
}
sprintf(s, "create table if not exists email ("
" username varchar(32),"
" content blob,"
" primary key (username)"
");");
if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
lwsl_err("Unable to create user table: %s\n",
sqlite3_errmsg(vhd->pdb));
return 1;
}
lws_email_init(&vhd->email, lws_uv_getloop(vhd->context, 0),
LWSGS_EMAIL_CONTENT_SIZE);
vhd->email_inited = 1;
break;
case LWS_CALLBACK_PROTOCOL_DESTROY:
// lwsl_notice("gs: LWS_CALLBACK_PROTOCOL_DESTROY: v=%p, ctx=%p\n", vhd, vhd->context);
if (vhd->pdb) {
sqlite3_close(vhd->pdb);
vhd->pdb = NULL;
}
if (vhd->email_inited) {
lws_email_destroy(&vhd->email);
vhd->email_inited = 0;
}
break;
case LWS_CALLBACK_HTTP:
lwsl_info("LWS_CALLBACK_HTTP: %s\n", (const char *)in);
pss->login_session.id[0] = '\0';
pss->phs.pos = 0;
strncpy(pss->onward, (char *)in, sizeof(pss->onward) - 1);
pss->onward[sizeof(pss->onward) - 1] = '\0';
if (!strcmp((const char *)in, "/lwsgs-forgot")) {
lwsgs_handler_forgot(vhd, wsi, pss);
goto redirect_with_cookie;
}
if (!strcmp((const char *)in, "/lwsgs-confirm")) {
lwsgs_handler_confirm(vhd, wsi, pss);
goto redirect_with_cookie;
}
if (!strcmp((const char *)in, "/lwsgs-check")) {
lwsgs_handler_check(vhd, wsi, pss);
goto try_to_reuse;
}
if (!strcmp((const char *)in, "/lwsgs-login"))
break;
if (!strcmp((const char *)in, "/lwsgs-logout"))
break;
if (!strcmp((const char *)in, "/lwsgs-forgot"))
break;
if (!strcmp((const char *)in, "/lwsgs-change"))
break;
/* if no legitimate url for GET, return 404 */
lwsl_err("http doing 404 on %s\n", (const char *)in);
lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
goto try_to_reuse;
case LWS_CALLBACK_CHECK_ACCESS_RIGHTS:
n = 0;
username[0] = '\0';
sid.id[0] = '\0';
args = (struct lws_process_html_args *)in;
lwsl_debug("LWS_CALLBACK_CHECK_ACCESS_RIGHTS\n");
if (!lwsgs_get_sid_from_wsi(wsi, &sid)) {
if (lwsgs_lookup_session(vhd, &sid, username, sizeof(username))) {
static const char * const oprot[] = {
"http://", "https://"
};
lwsl_notice("session lookup for %s failed, probably expired\n", sid.id);
pss->delete_session = sid;
args->final = 1; /* signal we dealt with it */
if (lws_hdr_copy(wsi, cookie, sizeof(cookie) - 1,
WSI_TOKEN_HOST) < 0)
return 1;
lws_snprintf(pss->onward, sizeof(pss->onward) - 1,
"%s%s%s", oprot[lws_is_ssl(wsi)],
cookie, args->p);
lwsl_notice("redirecting to ourselves with cookie refresh\n");
/* we need a redirect to ourselves, session cookie is expired */
goto redirect_with_cookie;
}
} else
lwsl_notice("failed to get sid from wsi\n");
n = lwsgs_get_auth_level(vhd, username);
if ((args->max_len & n) != args->max_len) {
lwsl_notice("Access rights fail 0x%X vs 0x%X (cookie %s)\n",
args->max_len, n, sid.id);
return 1;
}
lwsl_debug("Access rights OK\n");
break;
case LWS_CALLBACK_SESSION_INFO:
{
struct lwsgs_user u;
sinfo = (struct lws_session_info *)in;
sinfo->username[0] = '\0';
sinfo->email[0] = '\0';
sinfo->ip[0] = '\0';
sinfo->session[0] = '\0';
sinfo->mask = 0;
sid.id[0] = '\0';
lwsl_debug("LWS_CALLBACK_SESSION_INFO\n");
if (lwsgs_get_sid_from_wsi(wsi, &sid))
break;
if (lwsgs_lookup_session(vhd, &sid, username, sizeof(username)))
break;
lws_snprintf(s, sizeof(s) - 1,
"select username, email from users where username='%s';",
username);
if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
SQLITE_OK) {
lwsl_err("Unable to lookup token: %s\n",
sqlite3_errmsg(vhd->pdb));
break;
}
strncpy(sinfo->username, u.username, sizeof(sinfo->username) - 1);
sinfo->username[sizeof(sinfo->username) - 1] = '\0';
strncpy(sinfo->email, u.email, sizeof(sinfo->email) - 1);
strncpy(sinfo->session, sid.id, sizeof(sinfo->session) - 1);
sinfo->mask = lwsgs_get_auth_level(vhd, username);
lws_get_peer_simple(wsi, sinfo->ip, sizeof(sinfo->ip));
}
break;
case LWS_CALLBACK_PROCESS_HTML:
args = (struct lws_process_html_args *)in;
{
static const char * const vars[] = {
"$lwsgs_user",
"$lwsgs_auth",
"$lwsgs_email"
};
struct lwsgs_subst_args a;
a.vhd = vhd;
a.pss = pss;
a.wsi = wsi;
pss->phs.vars = vars;
pss->phs.count_vars = ARRAY_SIZE(vars);
pss->phs.replace = lwsgs_subst;
pss->phs.data = &a;
if (lws_chunked_html_process(args, &pss->phs))
return -1;
}
break;
case LWS_CALLBACK_HTTP_BODY:
if (len < 2)
break;
if (!pss->spa) {
pss->spa = lws_spa_create(wsi, param_names,
ARRAY_SIZE(param_names), 1024,
NULL, NULL);
if (!pss->spa)
return -1;
}
if (lws_spa_process(pss->spa, in, len)) {
lwsl_notice("spa process blew\n");
return -1;
}
break;
case LWS_CALLBACK_HTTP_BODY_COMPLETION:
if (!pss->spa)
break;
lwsl_info("LWS_CALLBACK_HTTP_BODY_COMPLETION: %s\n", pss->onward);
lws_spa_finalize(pss->spa);
if (!strcmp((char *)pss->onward, "/lwsgs-change")) {
if (!lwsgs_handler_change_password(vhd, wsi, pss)) {
cp = lws_spa_get_string(pss->spa, FGS_GOOD);
goto pass;
}
cp = lws_spa_get_string(pss->spa, FGS_BAD);
lwsl_notice("user/password no good %s\n",
lws_spa_get_string(pss->spa, FGS_USERNAME));
strncpy(pss->onward, cp, sizeof(pss->onward) - 1);
pss->onward[sizeof(pss->onward) - 1] = '\0';
goto completion_flow;
}
if (!strcmp((char *)pss->onward, "/lwsgs-login")) {
if (lws_spa_get_string(pss->spa, FGS_FORGOT) &&
lws_spa_get_string(pss->spa, FGS_FORGOT)[0]) {
if (lwsgs_handler_forgot_pw_form(vhd, wsi, pss)) {
n = FGS_FORGOT_BAD;
goto reg_done;
}
/* get the email monitor to take a look */
lws_email_check(&vhd->email);
n = FGS_FORGOT_GOOD;
goto reg_done;
}
if (!lws_spa_get_string(pss->spa, FGS_USERNAME) ||
!lws_spa_get_string(pss->spa, FGS_PASSWORD)) {
lwsl_notice("username '%s' or pw '%s' missing\n",
lws_spa_get_string(pss->spa, FGS_USERNAME),
lws_spa_get_string(pss->spa, FGS_PASSWORD));
return -1;
}
if (lws_spa_get_string(pss->spa, FGS_REGISTER) &&
lws_spa_get_string(pss->spa, FGS_REGISTER)[0]) {
if (lwsgs_handler_register_form(vhd, wsi, pss))
n = FGS_REG_BAD;
else {
n = FGS_REG_GOOD;
/* get the email monitor to take a look */
lws_email_check(&vhd->email);
}
reg_done:
strncpy(pss->onward, lws_spa_get_string(pss->spa, n),
sizeof(pss->onward) - 1);
pss->onward[sizeof(pss->onward) - 1] = '\0';
pss->login_expires = 0;
pss->logging_out = 1;
goto completion_flow;
}
/* we have the username and password... check if admin */
if (lwsgw_check_admin(vhd, lws_spa_get_string(pss->spa, FGS_USERNAME),
lws_spa_get_string(pss->spa, FGS_PASSWORD))) {
if (lws_spa_get_string(pss->spa, FGS_ADMIN))
cp = lws_spa_get_string(pss->spa, FGS_ADMIN);
else
if (lws_spa_get_string(pss->spa, FGS_GOOD))
cp = lws_spa_get_string(pss->spa, FGS_GOOD);
else {
lwsl_info("No admin or good target url in form\n");
return -1;
}
lwsl_debug("admin\n");
goto pass;
}
/* check users in database */
if (!lwsgs_check_credentials(vhd, lws_spa_get_string(pss->spa, FGS_USERNAME),
lws_spa_get_string(pss->spa, FGS_PASSWORD))) {
lwsl_info("pw hash check met\n");
cp = lws_spa_get_string(pss->spa, FGS_GOOD);
goto pass;
} else
lwsl_notice("user/password no good %s\n",
lws_spa_get_string(pss->spa, FGS_USERNAME));
if (!lws_spa_get_string(pss->spa, FGS_BAD)) {
lwsl_info("No admin or good target url in form\n");
return -1;
}
strncpy(pss->onward, lws_spa_get_string(pss->spa, FGS_BAD),
sizeof(pss->onward) - 1);
pss->onward[sizeof(pss->onward) - 1] = '\0';
lwsl_debug("failed\n");
goto completion_flow;
}
if (!strcmp((char *)pss->onward, "/lwsgs-logout")) {
lwsl_notice("/logout\n");
if (lwsgs_get_sid_from_wsi(wsi, &pss->login_session)) {
lwsl_notice("not logged in...\n");
return 1;
}
lwsgw_update_session(vhd, &pss->login_session, "");
if (!lws_spa_get_string(pss->spa, FGS_GOOD)) {
lwsl_info("No admin or good target url in form\n");
return -1;
}
strncpy(pss->onward, lws_spa_get_string(pss->spa, FGS_GOOD), sizeof(pss->onward) - 1);
pss->onward[sizeof(pss->onward) - 1] = '\0';
pss->login_expires = 0;
pss->logging_out = 1;
goto completion_flow;
}
break;
pass:
strncpy(pss->onward, cp, sizeof(pss->onward) - 1);
pss->onward[sizeof(pss->onward) - 1] = '\0';
if (lwsgs_get_sid_from_wsi(wsi, &sid))
sid.id[0] = '\0';
pss->login_expires = lws_now_secs() +
vhd->timeout_absolute_secs;
if (!sid.id[0]) {
/* we need to create a new, authorized session */
if (lwsgs_new_session_id(vhd, &pss->login_session,
lws_spa_get_string(pss->spa, FGS_USERNAME),
pss->login_expires))
goto try_to_reuse;
lwsl_info("Creating new session: %s\n",
pss->login_session.id);
} else {
/*
* we can just update the existing session to be
* authorized
*/
lwsl_info("Authorizing existing session %s", sid.id);
lwsgw_update_session(vhd, &sid,
lws_spa_get_string(pss->spa, FGS_USERNAME));
pss->login_session = sid;
}
completion_flow:
lwsgw_expire_old_sessions(vhd);
goto redirect_with_cookie;
case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
if (pss && pss->spa) {
lws_spa_destroy(pss->spa);
pss->spa = NULL;
}
break;
case LWS_CALLBACK_ADD_HEADERS:
lwsgw_expire_old_sessions(vhd);
args = (struct lws_process_html_args *)in;
if (pss->delete_session.id[0]) {
pc = cookie;
lwsgw_cookie_from_session(&pss->delete_session, 0, &pc,
cookie + sizeof(cookie) - 1);
lwsl_info("deleting cookie '%s'\n", cookie);
if (lws_add_http_header_by_name(wsi,
(unsigned char *)"set-cookie:",
(unsigned char *)cookie, pc - cookie,
(unsigned char **)&args->p,
(unsigned char *)args->p + args->max_len))
return 1;
}
if (!pss->login_session.id[0])
lwsgs_get_sid_from_wsi(wsi, &pss->login_session);
if (!pss->login_session.id[0] && !pss->logging_out) {
pss->login_expires = lws_now_secs() +
vhd->timeout_anon_absolute_secs;
if (lwsgs_new_session_id(vhd, &pss->login_session, "",
pss->login_expires))
goto try_to_reuse;
pc = cookie;
lwsgw_cookie_from_session(&pss->login_session,
pss->login_expires, &pc,
cookie + sizeof(cookie) - 1);
lwsl_info("LWS_CALLBACK_ADD_HEADERS: setting cookie '%s'\n", cookie);
if (lws_add_http_header_by_name(wsi,
(unsigned char *)"set-cookie:",
(unsigned char *)cookie, pc - cookie,
(unsigned char **)&args->p,
(unsigned char *)args->p + args->max_len))
return 1;
}
break;
default:
break;
}
return 0;
redirect_with_cookie:
p = buffer + LWS_PRE;
start = p;
end = p + sizeof(buffer) - LWS_PRE;
if (lws_add_http_header_status(wsi, HTTP_STATUS_SEE_OTHER, &p, end))
return 1;
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_LOCATION,
(unsigned char *)pss->onward,
strlen(pss->onward), &p, end))
return 1;
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
(unsigned char *)"text/html", 9, &p, end))
return 1;
if (lws_add_http_header_content_length(wsi, 0, &p, end))
return 1;
if (pss->delete_session.id[0]) {
lwsgw_cookie_from_session(&pss->delete_session, 0, &pc,
cookie + sizeof(cookie) - 1);
lwsl_notice("deleting cookie '%s'\n", cookie);
if (lws_add_http_header_by_name(wsi,
(unsigned char *)"set-cookie:",
(unsigned char *)cookie, pc - cookie,
&p, end))
return 1;
}
if (!pss->login_session.id[0]) {
pss->login_expires = lws_now_secs() +
vhd->timeout_anon_absolute_secs;
if (lwsgs_new_session_id(vhd, &pss->login_session, "",
pss->login_expires))
return 1;
} else
pss->login_expires = lws_now_secs() +
vhd->timeout_absolute_secs;
if (pss->login_session.id[0] || pss->logging_out) {
/*
* we succeeded to login, we must issue a login
* cookie with the prepared data
*/
pc = cookie;
lwsgw_cookie_from_session(&pss->login_session,
pss->login_expires, &pc,
cookie + sizeof(cookie) - 1);
lwsl_info("setting cookie '%s'\n", cookie);
pss->logging_out = 0;
if (lws_add_http_header_by_name(wsi,
(unsigned char *)"set-cookie:",
(unsigned char *)cookie, pc - cookie,
&p, end))
return 1;
}
if (lws_finalize_http_header(wsi, &p, end))
return 1;
n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
if (n < 0)
return 1;
/* fallthru */
try_to_reuse:
if (lws_http_transaction_completed(wsi))
return -1;
return 0;
}
static const struct lws_protocols protocols[] = {
{
"protocol-generic-sessions",
callback_generic_sessions,
sizeof(struct per_session_data__gs),
1024,
},
};
LWS_EXTERN LWS_VISIBLE int
init_protocol_generic_sessions(struct lws_context *context,
struct lws_plugin_capability *c)
{
if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
c->api_magic);
return 1;
}
c->protocols = protocols;
c->count_protocols = ARRAY_SIZE(protocols);
c->extensions = NULL;
c->count_extensions = 0;
return 0;
}
LWS_EXTERN LWS_VISIBLE int
destroy_protocol_generic_sessions(struct lws_context *context)
{
return 0;
}