aboutsummaryrefslogtreecommitdiff
path: root/ctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'ctl.c')
-rw-r--r--ctl.c171
1 files changed, 97 insertions, 74 deletions
diff --git a/ctl.c b/ctl.c
index 9583c44..39581c2 100644
--- a/ctl.c
+++ b/ctl.c
@@ -1,41 +1,16 @@
#include <err.h>
+#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
+#include <unistd.h>
#include "cforum.h"
#define MAXMSG 256
-/* Print UNIX timestamp as written date. */
-void
-printdate(int timestamp)
-{
- char buf[20];
- struct tm *t;
-
- t = localtime((time_t *)&timestamp);
- strftime(buf, 20, "%Y-%m-%d %H:%M", t);
-
- printf(buf);
-}
-
-/* Print HTML-escaped string. */
-void
-printhtml(char *s)
-{
- char *t;
-
- for(t = s; *t; t++)
- switch(*t){
- case '&': printf("&amp;"); break;
- case '\"': printf("&quot;"); break;
- case '\'': printf("&apos;"); break;
- case '<': printf("&lt;"); break;
- case '>': printf("&gt;"); break;
- default: printf("%c", *t);
- }
-}
+static void printdate(int);
+static void printhtml(char *);
/*
* The `new' functions provide a way to add a new attachment/post/user.
@@ -53,21 +28,26 @@ newpost()
void
newsession()
{
- char *hlite, msg[MAXMSG], *p, *v;
+ char *hlite, *home, msg[MAXMSG], *p, rnd[MAXCOOKIE], *v;
char *name, *pass, *remember;
- char title[] = "Log In";
struct user *user;
+ struct session session;
sqlite3_stmt *stmt;
-
+
+ char title[] = "Log In";
+
*msg = 0;
hlite = name = pass = remember = NULL;
-
+
+ home = getenv("REQUEST_URI");
+ home[strcspn(home, "?")] = 0;
+
if(query.method == GET){
printf("Content-Type: text/html\n\n");
#include "t/login.tc"
return;
}
-
+
if(query.length > MAXSESSIONDATA){
snprintf(msg, MAXMSG, "Input exceeded server limitations");
printf("Status: 431 Request Header Fields Too Large\n");
@@ -75,10 +55,10 @@ newsession()
#include "t/login.tc"
return;
}
-
+
while(p = nextparam(POST, NULL, MAXSESSIONDATA)){
if(!(v = split(p))) continue;
-
+
if(!name && strcmp(p, "name") == 0)
name = strdup(v);
else if(!pass && strcmp(p, "pass") == 0)
@@ -88,7 +68,7 @@ newsession()
else
continue;
}
-
+
if(!name || !*name){
snprintf(msg, MAXMSG, "Username may not be empty");
printf("Status: 400 Bad Request\n");
@@ -96,28 +76,42 @@ newsession()
#include "t/login.tc"
return;
}
-
- if(sqlite3_prepare(db, "SELECT oid, * from users WHERE name = ?",
+
+ if(sqlite3_prepare(db, "SELECT oid, * FROM users WHERE name = ?",
-1, &stmt, 0) != SQLITE_OK)
goto fail;
-
+
if(sqlite3_bind_text(stmt, 1, name, -1, SQLITE_STATIC) != SQLITE_OK)
goto dberr;
-
+
if(!(user = getuser(stmt)))
goto fail;
-
+
if(!haspass(user, pass))
goto fail;
+
+ /* Create session cookie. */
+ makerandom(rnd, sizeof(rnd));
+ session.user = user->id;
+ session.string = rnd;
+ if(!addsession(&session)){
+ snprintf(msg, MAXMSG, "Could not create session for user");
+ printf("Status: 500 Internal Server Error");
+ printf("Content-Type: text/html\n\n");
+ #include "t/login.tc"
+ return;
+ }
- printf("Content-Type: text/plain\n\n");
- printf("Success!\n");
+ printf("Status: 303 See Other\n");
+ printf("Set-Cookie: user=%d\n", user->id);
+ printf("Set-Cookie: session=%s\n", rnd);
+ printf("Location: %s\n\n", home);
return;
dberr:
snprintf(msg, MAXMSG, "Could not retrieve user: %s",
sqlite3_errmsg(db));
- printf("Status: 500 Internal Server Errror\n");
+ printf("Status: 500 Internal Server Error\n");
printf("Content-Type: text/html\n\n");
#include "t/login.tc"
return;
@@ -136,16 +130,16 @@ newuser()
char title[] = "New User";
int i;
struct user *user;
-
+
*msg = 0;
captcha = confirm = hlite = name = full = pass = NULL;
-
+
if(query.method == GET){
printf("Content-Type: text/html\n\n");
#include "t/newuser.tc"
return;
}
-
+
if(query.length > MAXUSERDATA){
snprintf(msg, MAXMSG, "Input exceeded server limitations");
printf("Status: 431 Request Header Fields Too Large\n");
@@ -153,10 +147,10 @@ newuser()
#include "t/newuser.tc"
return;
}
-
+
while(p = nextparam(POST, NULL, MAXUSERDATA)){
if(!(v = split(p))) continue;
-
+
if(!captcha && strcmp(p, "captcha") == 0)
captcha = strdup(v);
if(!confirm && strcmp(p, "confirm") == 0)
@@ -170,7 +164,7 @@ newuser()
else
continue;
}
-
+
/* Decode URL-encoded fields. */
if(captcha && *captcha)
captcha[urldecode(captcha, -1)] = 0;
@@ -182,7 +176,7 @@ newuser()
full[urldecode(full, -1)] = 0;
if(pass && *pass)
pass[urldecode(pass, -1)] = 0;
-
+
/* Constrain lengths of decoded fields. */
if(name && *name && strlen(name)-1 > MAXUSERNAME){
hlite = strdup("name");
@@ -202,10 +196,10 @@ newuser()
MAXUSERPASS-1);
goto err;
}
-
+
#define ISVIS(c) ((unsigned char)c >= 32)
#define ISALNUM(c) (c>='A' && c<='Z' || c>='a' && c<='z' || c>='0' && c<='9')
-
+
/* Constrain character sets. */
for(i = 0; name[i]; i++)
if(!name[i] == '_' && !ISALNUM(name[i])){
@@ -217,13 +211,12 @@ newuser()
}
for(i = 0; full[i]; i++)
if(!ISVIS(full[i])){
- fprintf(stderr, "%d\n", full[i]);
hlite = strdup("full");
snprintf(msg, MAXMSG,
"Full name may only contain visible characters");
goto err;
}
-
+
/* Validate captcha. */
if(captcha && strcmp(captcha, "9") != 0){
hlite = strdup("captcha");
@@ -247,14 +240,14 @@ newuser()
snprintf(msg, MAXMSG, "Passwords do not match");
goto err;
}
-
+
if(!(user = malloc(sizeof(struct user))))
err(1, "malloc");
-
+
user->name = name;
user->full = *full? full: NULL;
makehash(pass, &user->hash, &user->salt);
-
+
if(!adduser(user)){
if(strcmp(sqlite3_errmsg(db), "column name is not unique")==0)
snprintf(msg, MAXMSG, "Username already exists.");
@@ -263,7 +256,7 @@ newuser()
sqlite3_errmsg(db));
goto err;
}
-
+
printf("Content-Type: text/html\n\n");
snprintf(msg, MAXMSG, "SUCCESS: User was added to database");
#include "t/newuser.tc"
@@ -275,6 +268,36 @@ err:
return;
}
+/* Print UNIX timestamp as written date. */
+void
+printdate(int timestamp)
+{
+ char buf[20];
+ struct tm *t;
+
+ t = localtime((time_t *)&timestamp);
+ strftime(buf, 20, "%Y-%m-%d %H:%M", t);
+
+ printf(buf);
+}
+
+/* Print HTML-escaped string. */
+void
+printhtml(char *s)
+{
+ char *t;
+
+ for(t = s; *t; t++)
+ switch(*t){
+ case '&': printf("&amp;"); break;
+ case '\"': printf("&quot;"); break;
+ case '\'': printf("&apos;"); break;
+ case '<': printf("&lt;"); break;
+ case '>': printf("&gt;"); break;
+ default: printf("%c", *t);
+ }
+}
+
/*
* The `show' functions show an existing attachment/post/user
* or some other type of page.
@@ -283,12 +306,12 @@ void
showatt(id)
{
struct att *att;
-
+
if(!(att = getatt(selectbyint("atts", "oid", id)))){
srverr("Could not retrieve attachment");
return;
}
-
+
printf("Content-Type: %s\n\n", att->mime);
printf("%.*s", att->bytes, att->data);
free(att);
@@ -301,21 +324,21 @@ showfront()
struct post *post;
struct user *user;
sqlite3_stmt *pstmt, *ustmt;
-
+
if(sqlite3_prepare(db,
"SELECT oid, * from posts ORDER BY created DESC",
-1, &pstmt, 0) != SQLITE_OK){
srverr("Could not retrieve posts");
return;
}
-
+
if(sqlite3_prepare(db,
"SELECT oid, * from users ORDER BY created DESC",
-1, &ustmt, 0) != SQLITE_OK){
srverr("Could not retrieve users");
return;
}
-
+
title = site.name;
printf("Content-Type: text/html\n\n");
#include "t/front.tc"
@@ -329,19 +352,19 @@ showpost(int id)
struct post *post;
struct user *user;
sqlite3_stmt *stmt;
-
+
if(!(post = getpost(selectbyint("posts", "oid", id)))){
srverr("Could not retrieve post");
return;
}
-
+
if(!(user = getuser(selectbyint("users", "oid", post->user)))){
srverr("Could not retrieve post author");
return;
}
-
+
stmt = selectbyint("atts", "post", id);
-
+
title = post->subject;
printf("Content-Type: text/html\n\n");
#include "t/post.tc"
@@ -356,26 +379,26 @@ showuser(int id)
sqlite3_stmt *stmt;
struct post *post;
struct user *user;
-
+
if(!(user = getuser(selectbyint("users", "oid", id)))){
srverr("Could not retrieve user");
return;
}
-
+
if(sqlite3_prepare(db,
"SELECT oid, * from posts WHERE user = ? ORDER BY created DESC",
-1, &stmt, 0) != SQLITE_OK)
goto err;
-
+
if(sqlite3_bind_int(stmt, 1, id) != SQLITE_OK)
goto err;
-
+
snprintf(title, 120, "User: %s", user->full? user->full: user->name);
printf("Content-Type: text/html\n\n");
#include "t/user.tc"
free(user);
return;
-
+
err:
srverr("Could not retrieve posts");
return;