| /* |
| * 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; |
| } |