• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include "private-lwsgs.h"
26 
27 #if defined(LWS_WITH_SMTP)
28 
29 static int
lwsgs_smtp_client_done(struct lws_smtp_email * e,void * buf,size_t len)30 lwsgs_smtp_client_done(struct lws_smtp_email *e, void *buf, size_t len)
31 {
32 	free(e);
33 
34 	return 0;
35 }
36 
37 static int
lwsgs_smtp_client_done_sentvfy(struct lws_smtp_email * e,void * buf,size_t len)38 lwsgs_smtp_client_done_sentvfy(struct lws_smtp_email *e, void *buf, size_t len)
39 {
40 	struct per_vhost_data__gs *vhd = (struct per_vhost_data__gs *)e->data;
41 	const char *username = (const char *)e->extra;
42 	char s[200], esc[96];
43 
44 	lwsl_notice("%s: registration email sent: %s\n", __func__, username);
45 
46 	/* mark the user as having sent the verification email */
47 	lws_snprintf(s, sizeof(s) - 1,
48 		 "update users set verified=1 where username='%s' and verified==0;",
49 		 lws_sql_purify(esc, username, sizeof(esc) - 1));
50 	if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
51 		lwsl_err("%s: Unable to update user: %s\n", __func__,
52 			 sqlite3_errmsg(vhd->pdb));
53 		return 1;
54 	}
55 
56 	free(e);
57 
58 	return 0;
59 }
60 #endif
61 
62 /* handle account confirmation links */
63 
64 int
lwsgs_handler_confirm(struct per_vhost_data__gs * vhd,struct lws * wsi,struct per_session_data__gs * pss)65 lwsgs_handler_confirm(struct per_vhost_data__gs *vhd, struct lws *wsi,
66 		      struct per_session_data__gs *pss)
67 {
68 	char cookie[1024], s[256], esc[90];
69 	struct lws_gs_event_args a;
70 	struct lwsgs_user u;
71 
72 	if (lws_hdr_copy_fragment(wsi, cookie, sizeof(cookie),
73 				  WSI_TOKEN_HTTP_URI_ARGS, 0) < 0) {
74 		lwsl_err("%s: missing URI_ARGS\n", __func__);
75 		goto verf_fail;
76 	}
77 
78 	if (strncmp(cookie, "token=", 6)) {
79 		lwsl_err("%s: missing URI_ARGS token=\n", __func__);
80 		goto verf_fail;
81 	}
82 
83 	u.username[0] = '\0';
84 	u.verified = -1;
85 	lws_snprintf(s, sizeof(s) - 1,
86 		 "select username,email,verified from users where token = '%s';",
87 		 lws_sql_purify(esc, &cookie[6], sizeof(esc) - 1));
88 	puts(s);
89 	if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
90 	    SQLITE_OK) {
91 		lwsl_err("Unable to lookup token: %s\n",
92 			 sqlite3_errmsg(vhd->pdb));
93 		goto verf_fail;
94 	}
95 
96 	if (!u.username[0] || u.verified != 1) {
97 		lwsl_notice("verify token %s doesn't map to unverified user (user='%s', verified=%d)\n",
98 				&cookie[6], u.username, u.verified);
99 		goto verf_fail;
100 	}
101 
102 	lwsl_notice("Verifying %s\n", u.username);
103 	lws_snprintf(s, sizeof(s) - 1,
104 		 "update users set verified=%d where username='%s';",
105 		 LWSGS_VERIFIED_ACCEPTED,
106 		 lws_sql_purify(esc, u.username, sizeof(esc) - 1));
107 	if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
108 	    SQLITE_OK) {
109 		lwsl_err("Unable to lookup token: %s\n",
110 			 sqlite3_errmsg(vhd->pdb));
111 
112 		goto verf_fail;
113 	}
114 
115 	lwsl_notice("deleting account\n");
116 
117 	a.event = LWSGSE_CREATED;
118 	a.username = u.username;
119 	a.email = u.email;
120 	lws_callback_vhost_protocols_vhost(lws_get_vhost(wsi),
121 					   LWS_CALLBACK_GS_EVENT, &a, 0);
122 
123 	lws_snprintf(pss->onward, sizeof(pss->onward),
124 		 "%s/post-verify-ok.html", vhd->email_confirm_url);
125 
126 	pss->login_expires = lws_now_secs() + vhd->timeout_absolute_secs;
127 
128 	pss->delete_session.id[0] = '\0';
129 	lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
130 
131 	/* we need to create a new, authorized session */
132 
133 	if (lwsgs_new_session_id(vhd, &pss->login_session, u.username,
134 				 pss->login_expires))
135 		goto verf_fail;
136 
137 	lwsl_notice("Creating new session: %s, redir to %s\n",
138 		    pss->login_session.id, pss->onward);
139 
140 	return 0;
141 
142 verf_fail:
143 	pss->delete_session.id[0] = '\0';
144 	lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
145 	pss->login_expires = 0;
146 
147 	lws_snprintf(pss->onward, sizeof(pss->onward), "%s/post-verify-fail.html",
148 		 vhd->email_confirm_url);
149 
150 	return 1;
151 }
152 
153 /* handle forgot password confirmation links */
154 
155 int
lwsgs_handler_forgot(struct per_vhost_data__gs * vhd,struct lws * wsi,struct per_session_data__gs * pss)156 lwsgs_handler_forgot(struct per_vhost_data__gs *vhd, struct lws *wsi,
157 		     struct per_session_data__gs *pss)
158 {
159 	char cookie[1024], s[256], esc[96];
160 	struct lwsgs_user u;
161 	const char *a;
162 
163 	a = lws_get_urlarg_by_name(wsi, "token=", cookie, sizeof(cookie));
164 	if (!a)
165 		goto forgot_fail;
166 
167 	u.username[0] = '\0';
168 	lws_snprintf(s, sizeof(s) - 1,
169 		 "select username,verified from users where verified=%d and "
170 		 "token = '%s' and token_time != 0;",
171 		 LWSGS_VERIFIED_ACCEPTED,
172 		 lws_sql_purify(esc, &cookie[6], sizeof(esc) - 1));
173 	if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
174 	    SQLITE_OK) {
175 		lwsl_err("Unable to lookup token: %s\n",
176 			 sqlite3_errmsg(vhd->pdb));
177 
178 		goto forgot_fail;
179 	}
180 
181 	if (!u.username[0]) {
182 		puts(s);
183 		lwsl_notice("forgot token doesn't map to verified user\n");
184 		goto forgot_fail;
185 	}
186 
187 	/* mark user as having validated forgot flow just now */
188 
189 	lws_snprintf(s, sizeof(s) - 1,
190 		 "update users set token_time=0,last_forgot_validated=%lu "
191 		 "where username='%s';",
192 		 (unsigned long)lws_now_secs(),
193 		 lws_sql_purify(esc, u.username, sizeof(esc) - 1));
194 
195 	if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
196 	    SQLITE_OK) {
197 		lwsl_err("Unable to lookup token: %s\n",
198 			 sqlite3_errmsg(vhd->pdb));
199 		goto forgot_fail;
200 	}
201 
202 	a = lws_get_urlarg_by_name(wsi, "good=", cookie, sizeof(cookie));
203 	if (!a)
204 		a = "broken-forget-post-good-url";
205 
206 	lws_snprintf(pss->onward, sizeof(pss->onward),
207 		 "%s/%s", vhd->email_confirm_url, a);
208 
209 	pss->login_expires = lws_now_secs() + vhd->timeout_absolute_secs;
210 
211 	pss->delete_session.id[0] = '\0';
212 	lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
213 
214 	/* we need to create a new, authorized session */
215 	if (lwsgs_new_session_id(vhd, &pss->login_session,
216 				 u.username,
217 				 pss->login_expires))
218 		goto forgot_fail;
219 
220 	lwsl_notice("Creating new session: %s, redir to %s\n",
221 		    pss->login_session.id, pss->onward);
222 
223 	return 0;
224 
225 forgot_fail:
226 	pss->delete_session.id[0] = '\0';
227 	lwsgs_get_sid_from_wsi(wsi, &pss->delete_session);
228 	pss->login_expires = 0;
229 
230 	a = lws_get_urlarg_by_name(wsi, "bad=", cookie, sizeof(cookie));
231 	if (!a)
232 		a = "broken-forget-post-bad-url";
233 
234 	lws_snprintf(pss->onward, sizeof(pss->onward), "%s/%s",
235 		 vhd->email_confirm_url, a);
236 
237 	return 1;
238 }
239 
240 /* support dynamic username / email checking */
241 
242 int
lwsgs_handler_check(struct per_vhost_data__gs * vhd,struct lws * wsi,struct per_session_data__gs * pss,const char * in)243 lwsgs_handler_check(struct per_vhost_data__gs *vhd,
244 		    struct lws *wsi, struct per_session_data__gs *pss,
245 		    const char *in)
246 {
247 	static const char * const colname[] = { "username", "email" };
248 	char s[256], esc[96], *pc;
249 	unsigned char *p, *start, *end, buffer[LWS_PRE + 1024];
250 	struct lwsgs_user u;
251 	int n;
252 
253 	/*
254 	 * either /check/email=xxx@yyy   or: /check/username=xxx
255 	 * returns '0' if not already registered, else '1'
256 	 */
257 
258 	u.username[0] = '\0';
259 
260 	n = !strncmp(in, "email=", 6);
261 	pc = strchr(in, '=');
262 	if (!pc) {
263 		lwsl_notice("cookie has no =\n");
264 		goto reply;
265 	}
266 	pc++;
267 
268 	/* admin user cannot be registered in user db */
269 	if (!strcmp(vhd->admin_user, pc)) {
270 		u.username[0] = 'a';
271 		goto reply;
272 	}
273 
274 	lws_snprintf(s, sizeof(s) - 1,
275 		 "select username, email from users where %s = '%s';",
276 		 colname[n], lws_sql_purify(esc, pc, sizeof(esc) - 1));
277 	if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
278 	    SQLITE_OK) {
279 		lwsl_err("Unable to lookup token: %s\n",
280 			 sqlite3_errmsg(vhd->pdb));
281 		goto reply;
282 	}
283 
284 reply:
285 	s[0] = '0' + !!u.username[0];
286 	p = buffer + LWS_PRE;
287 	start = p;
288 	end = p + sizeof(buffer) - LWS_PRE;
289 
290 	if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
291 		return -1;
292 	if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
293 					 (unsigned char *)"text/plain", 10,
294 					 &p, end))
295 		return -1;
296 
297 	if (lws_add_http_header_content_length(wsi, 1, &p, end))
298 		return -1;
299 
300 	if (lws_finalize_http_header(wsi, &p, end))
301 		return -1;
302 
303 	n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
304 	if (n != (p - start)) {
305 		lwsl_err("_write returned %d from %ld\n", n, (long)(p - start));
306 		return -1;
307 	}
308 
309 	pss->check_response_value = s[0];
310 	pss->check_response = 1;
311 
312 	lws_callback_on_writable(wsi);
313 
314 	return 0;
315 }
316 
317 /* handle forgot password confirmation links */
318 
319 int
lwsgs_handler_change_password(struct per_vhost_data__gs * vhd,struct lws * wsi,struct per_session_data__gs * pss)320 lwsgs_handler_change_password(struct per_vhost_data__gs *vhd, struct lws *wsi,
321 			      struct per_session_data__gs *pss)
322 {
323 	char s[256], esc[96], username[96];
324 	struct lwsgs_user u;
325 	lwsgw_hash sid;
326 	int n = 0;
327 
328 	/* see if he's logged in */
329 	username[0] = '\0';
330 	if (!lwsgs_get_sid_from_wsi(wsi, &sid)) {
331 		u.username[0] = '\0';
332 		if (!lwsgs_lookup_session(vhd, &sid, username, sizeof(username))) {
333 			n = 1; /* yes, logged in */
334 			if (lwsgs_lookup_user(vhd, username, &u))
335 				return 1;
336 
337 			/* did a forgot pw ? */
338 			if (u.last_forgot_validated > (time_t)lws_now_secs() - 300) {
339 				n |= LWSGS_AUTH_FORGOT_FLOW;
340 				lwsl_debug("within forgot password flow\n");
341 			}
342 		}
343 	}
344 
345 	lwsl_debug("auth value %d\n", n);
346 
347 	/* if he just did forgot pw flow, don't need old pw */
348 	if ((n & (LWSGS_AUTH_FORGOT_FLOW | 1)) != (LWSGS_AUTH_FORGOT_FLOW | 1)) {
349 		/* otherwise user:pass must be right */
350 		lwsl_debug("checking pw\n");
351 		if (lwsgs_check_credentials(vhd,
352 			   lws_spa_get_string(pss->spa, FGS_USERNAME),
353 			   lws_spa_get_string(pss->spa, FGS_CURPW))) {
354 			lwsl_notice("credentials bad\n");
355 			return 1;
356 		}
357 
358 		lwsl_debug("current pw checks out\n");
359 
360 		lws_strncpy(u.username, lws_spa_get_string(pss->spa, FGS_USERNAME),
361 			    sizeof(u.username));
362 	}
363 
364 	/* does he want to delete his account? */
365 
366 	if (lws_spa_get_length(pss->spa, FGS_DELETE)) {
367 		struct lws_gs_event_args a;
368 
369 		lwsl_notice("deleting account\n");
370 
371 		a.event = LWSGSE_DELETED;
372 		a.username = u.username;
373 		a.email = "";
374 		lws_callback_vhost_protocols_vhost(lws_get_vhost(wsi),
375 						   LWS_CALLBACK_GS_EVENT, &a, 0);
376 
377 		lws_snprintf(s, sizeof(s) - 1,
378 			 "delete from users where username='%s';"
379 			 "delete from sessions where username='%s';",
380 			 lws_sql_purify(esc, u.username, sizeof(esc) - 1),
381 			 lws_sql_purify(esc, u.username, sizeof(esc) - 1));
382 		goto sql;
383 	}
384 
385 	if (lwsgs_hash_password(vhd, lws_spa_get_string(pss->spa, FGS_PASSWORD), &u))
386 		return 1;
387 
388 	lwsl_notice("updating password hash\n");
389 
390 	lws_snprintf(s, sizeof(s) - 1,
391 		 "update users set pwhash='%s', pwsalt='%s', "
392 		 "last_forgot_validated=0 where username='%s';",
393 		 u.pwhash.id, u.pwsalt.id,
394 		 lws_sql_purify(esc, u.username, sizeof(esc) - 1));
395 
396 sql:
397 	if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
398 		lwsl_err("Unable to update pw hash: %s\n",
399 			 sqlite3_errmsg(vhd->pdb));
400 		return 1;
401 	}
402 
403 	return 0;
404 }
405 
406 int
lwsgs_handler_forgot_pw_form(struct per_vhost_data__gs * vhd,struct lws * wsi,struct per_session_data__gs * pss)407 lwsgs_handler_forgot_pw_form(struct per_vhost_data__gs *vhd,
408 			     struct lws *wsi, struct per_session_data__gs *pss)
409 {
410 	char esc[96], esc1[96], esc2[96], esc3[96], esc4[96];
411 	char s[LWSGS_EMAIL_CONTENT_SIZE];
412 	unsigned char sid_rand[32];
413 #if defined(LWS_WITH_SMTP)
414 	lws_smtp_email_t *em;
415 #endif
416 	struct lwsgs_user u;
417 	lwsgw_hash hash;
418 	int n;
419 
420 	lwsl_notice("FORGOT %s %s\n",
421 		    lws_spa_get_string(pss->spa, FGS_USERNAME),
422 		    lws_spa_get_string(pss->spa, FGS_EMAIL));
423 
424 	if (!lws_spa_get_string(pss->spa, FGS_USERNAME) &&
425 	    !lws_spa_get_string(pss->spa, FGS_EMAIL)) {
426 		lwsl_err("Form must provide either "
427 			  "username or email\n");
428 		return -1;
429 	}
430 
431 	if (!lws_spa_get_string(pss->spa, FGS_FORGOT_GOOD) ||
432 	    !lws_spa_get_string(pss->spa, FGS_FORGOT_BAD) ||
433 	    !lws_spa_get_string(pss->spa, FGS_FORGOT_POST_GOOD) ||
434 	    !lws_spa_get_string(pss->spa, FGS_FORGOT_POST_BAD)) {
435 		lwsl_err("Form must provide reg-good "
436 			  "and reg-bad (and post-*)"
437 			  "targets\n");
438 		return -1;
439 	}
440 
441 	u.username[0] = '\0';
442 	if (lws_spa_get_string(pss->spa, FGS_USERNAME))
443 		lws_snprintf(s, sizeof(s) - 1,
444 		 "select username,email "
445 		 "from users where username = '%s';",
446 		 lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_USERNAME),
447 				 sizeof(esc) - 1));
448 	else
449 		lws_snprintf(s, sizeof(s) - 1,
450 		 "select username,email "
451 		 "from users where email = '%s';",
452 		 lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_EMAIL), sizeof(esc) - 1));
453 	if (sqlite3_exec(vhd->pdb, s, lwsgs_lookup_callback_user, &u, NULL) !=
454 	    SQLITE_OK) {
455 		lwsl_err("Unable to lookup token: %s\n",
456 			 sqlite3_errmsg(vhd->pdb));
457 		return 1;
458 	}
459 	if (!u.username[0]) {
460 		lwsl_err("No match found %s\n", s);
461 		return 1;
462 	}
463 
464 	lws_get_peer_simple(wsi, pss->ip, sizeof(pss->ip));
465 	if (lws_get_random(vhd->context, sid_rand,
466 			   sizeof(sid_rand)) !=
467 			   sizeof(sid_rand)) {
468 		lwsl_err("Problem getting random for token\n");
469 		return 1;
470 	}
471 	sha256_to_lwsgw_hash(sid_rand, &hash);
472 
473 	lws_snprintf(s, sizeof(s) - 1,
474 		 "update users set token='%s',token_time='%ld' where username='%s';",
475 		 hash.id, (long)lws_now_secs(),
476 		 lws_sql_purify(esc, u.username, sizeof(esc) - 1));
477 	if (sqlite3_exec(vhd->pdb, s, NULL, NULL, NULL) !=
478 	    SQLITE_OK) {
479 		lwsl_err("Unable to set token: %s\n",
480 			 sqlite3_errmsg(vhd->pdb));
481 		return 1;
482 	}
483 
484 	n = lws_snprintf(s, sizeof(s),
485 		"From: Forgot Password Assistant Noreply <%s>\n"
486 		"To: %s <%s>\n"
487 		  "Subject: Password reset request\n"
488 		  "\n"
489 		  "Hello, %s\n\n"
490 		  "We received a password reset request from IP %s for this email,\n"
491 		  "to confirm you want to do that, please click the link below.\n\n",
492 		lws_sql_purify(esc, vhd->email_from, sizeof(esc) - 1),
493 		lws_sql_purify(esc1, u.username, sizeof(esc1) - 1),
494 		lws_sql_purify(esc2, u.email, sizeof(esc2) - 1),
495 		lws_sql_purify(esc3, u.username, sizeof(esc3) - 1),
496 		lws_sql_purify(esc4, pss->ip, sizeof(esc4) - 1));
497 	lws_snprintf(s + n, sizeof(s) - n,
498 		  "%s/lwsgs-forgot?token=%s"
499 		   "&good=%s"
500 		   "&bad=%s\n\n"
501 		  "If this request is unexpected, please ignore it and\n"
502 		  "no further action will be taken.\n\n"
503 		"If you have any questions or concerns about this\n"
504 		"automated email, you can contact a real person at\n"
505 		"%s.\n"
506 		"\n.\n",
507 		vhd->email_confirm_url, hash.id,
508 		lws_urlencode(esc1,
509 			     lws_spa_get_string(pss->spa, FGS_FORGOT_POST_GOOD),
510 			     sizeof(esc1) - 1),
511 		lws_urlencode(esc3,
512 			      lws_spa_get_string(pss->spa, FGS_FORGOT_POST_BAD),
513 			      sizeof(esc3) - 1),
514 		vhd->email_contact_person);
515 
516 	puts(s);
517 #if defined(LWS_WITH_SMTP)
518 
519 	em = lws_smtpc_alloc_email_helper(s, n, vhd->email_from, u.email,
520 						u.username, strlen(u.username),
521 						vhd, lwsgs_smtp_client_done);
522 	if (!em)
523 		return 1;
524 	if (lws_smtpc_add_email(vhd->smtp_client, em))
525 		return 1;
526 #endif
527 	return 0;
528 }
529 
530 int
lwsgs_handler_register_form(struct per_vhost_data__gs * vhd,struct lws * wsi,struct per_session_data__gs * pss)531 lwsgs_handler_register_form(struct per_vhost_data__gs *vhd,
532 			     struct lws *wsi,
533 			     struct per_session_data__gs *pss)
534 {
535 	unsigned char buffer[LWS_PRE + LWSGS_EMAIL_CONTENT_SIZE];
536 	char esc[96], esc1[96], esc2[96], esc3[96], esc4[96];
537 	char s[LWSGS_EMAIL_CONTENT_SIZE];
538 	unsigned char sid_rand[32];
539 #if defined(LWS_WITH_SMTP)
540 	lws_smtp_email_t *em;
541 #endif
542 	struct lwsgs_user u;
543 	lwsgw_hash hash;
544 	size_t n;
545 
546 	lwsl_notice("REGISTER %s %s %s\n",
547 			lws_spa_get_string(pss->spa, FGS_USERNAME),
548 			lws_spa_get_string(pss->spa, FGS_PASSWORD),
549 			lws_spa_get_string(pss->spa, FGS_EMAIL));
550 	if (lwsgs_get_sid_from_wsi(wsi,
551 	    &pss->login_session))
552 		return 1;
553 
554 	lws_get_peer_simple(wsi, pss->ip, sizeof(pss->ip));
555 	lwsl_notice("IP=%s\n", pss->ip);
556 
557 	if (!lws_spa_get_string(pss->spa, FGS_REG_GOOD) ||
558 	    !lws_spa_get_string(pss->spa, FGS_REG_BAD)) {
559 		lwsl_info("Form must provide reg-good and reg-bad targets\n");
560 		return -1;
561 	}
562 
563 	/* admin user cannot be registered in user db */
564 	if (!strcmp(vhd->admin_user,
565 		    lws_spa_get_string(pss->spa, FGS_USERNAME)))
566 		return 1;
567 
568 	if (!lwsgs_lookup_user(vhd,
569 			lws_spa_get_string(pss->spa, FGS_USERNAME), &u)) {
570 		lwsl_notice("user %s already registered\n",
571 			    lws_spa_get_string(pss->spa, FGS_USERNAME));
572 		return 1;
573 	}
574 
575 	u.username[0] = '\0';
576 	lws_snprintf(s, sizeof(s) - 1, "select username, email from users where email = '%s';",
577 		 lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_EMAIL),
578 		 sizeof(esc) - 1));
579 
580 	if (sqlite3_exec(vhd->pdb, s,
581 			 lwsgs_lookup_callback_user, &u, NULL) != SQLITE_OK) {
582 		lwsl_err("Unable to lookup token: %s\n",
583 			 sqlite3_errmsg(vhd->pdb));
584 		return 1;
585 	}
586 
587 	if (u.username[0]) {
588 		lwsl_notice("email %s already in use\n",
589 			    lws_spa_get_string(pss->spa, FGS_USERNAME));
590 		return 1;
591 	}
592 
593 	if (lwsgs_hash_password(vhd, lws_spa_get_string(pss->spa, FGS_PASSWORD),
594 			        &u)) {
595 		lwsl_err("Password hash failed\n");
596 		return 1;
597 	}
598 
599 	if (lws_get_random(vhd->context, sid_rand, sizeof(sid_rand)) !=
600 	    sizeof(sid_rand)) {
601 		lwsl_err("Problem getting random for token\n");
602 		return 1;
603 	}
604 	sha256_to_lwsgw_hash(sid_rand, &hash);
605 
606 	lws_snprintf((char *)buffer, sizeof(buffer) - 1,
607 		 "insert into users(username,"
608 		 " creation_time, ip, email, verified,"
609 		 " pwhash, pwsalt, token, last_forgot_validated)"
610 		 " values ('%s', %lu, '%s', '%s', 0,"
611 		 " '%s', '%s', '%s', 0);",
612 		lws_sql_purify(esc, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(esc) - 1),
613 		(unsigned long)lws_now_secs(),
614 		lws_sql_purify(esc1, pss->ip, sizeof(esc1) - 1),
615 		lws_sql_purify(esc2, lws_spa_get_string(pss->spa, FGS_EMAIL), sizeof(esc2) - 1),
616 		u.pwhash.id, u.pwsalt.id, hash.id);
617 
618 	if (sqlite3_exec(vhd->pdb, (char *)buffer, NULL, NULL, NULL) != SQLITE_OK) {
619 		lwsl_err("Unable to insert user: %s\n",
620 			 sqlite3_errmsg(vhd->pdb));
621 		return 1;
622 	}
623 
624 	n = lws_snprintf(s, sizeof(s),
625 		"From: Noreply <%s>\n"
626 		"To: %s <%s>\n"
627 		"Subject: Registration verification\n"
628 		"\n"
629 		  "Hello, %s\n\n"
630 		  "We received a registration from IP %s using this email,\n"
631 		  "to confirm it is legitimate, please click the link below.\n\n"
632 		  "%s/lwsgs-confirm?token=%s\n\n"
633 		  "If this request is unexpected, please ignore it and\n"
634 		  "no further action will be taken.\n\n"
635 		"If you have any questions or concerns about this\n"
636 		"automated email, you can contact a real person at\n"
637 		"%s.\n"
638 		"\n.\n",
639 		lws_sql_purify(esc, vhd->email_from, sizeof(esc) - 1),
640 		lws_sql_purify(esc1, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(esc1) - 1),
641 		lws_sql_purify(esc2, lws_spa_get_string(pss->spa, FGS_EMAIL), sizeof(esc2) - 1),
642 		lws_sql_purify(esc3, lws_spa_get_string(pss->spa, FGS_USERNAME), sizeof(esc3) - 1),
643 		lws_sql_purify(esc4, pss->ip, sizeof(esc4) - 1),
644 		vhd->email_confirm_url, hash.id,
645 		vhd->email_contact_person);
646 
647 #if defined(LWS_WITH_SMTP)
648 	em = lws_smtpc_alloc_email_helper(s, n, vhd->email_from,
649 				lws_spa_get_string(pss->spa, FGS_EMAIL),
650 				lws_spa_get_string(pss->spa, FGS_USERNAME),
651 				strlen(lws_spa_get_string(pss->spa, FGS_USERNAME)),
652 				vhd, lwsgs_smtp_client_done_sentvfy);
653 	if (!em)
654 		return 1;
655 
656 	if (lws_smtpc_add_email(vhd->smtp_client, em))
657 		return 1;
658 #else
659 	(void)n;
660 #endif
661 
662 	return 0;
663 }
664