Пример #1
0
SLNSessionRef SLNSessionCreateInternal(SLNSessionCacheRef const cache, uint64_t const sessionID, byte_t const *const sessionKeyRaw, byte_t const *const sessionKeyEnc, uint64_t const userID, SLNMode const mode_trusted, strarg_t const username) {
	assert(cache);
	if(!mode_trusted) return NULL;
	SLNSessionRef session = calloc(1, sizeof(struct SLNSession));
	if(!session) return NULL;
	session->cache = cache;
	session->sessionID = sessionID;

	session->sessionKeyRaw = malloc(SESSION_KEY_LEN);
	session->sessionKeyEnc = malloc(SESSION_KEY_LEN);
	if(!session->sessionKeyRaw || !session->sessionKeyEnc) {
		SLNSessionRelease(&session);
		return NULL;
	}
	if(sessionKeyRaw) {
		memcpy(session->sessionKeyRaw, sessionKeyRaw, SESSION_KEY_LEN);
	} else {
		FREE(&session->sessionKeyRaw);
	}
	if(sessionKeyEnc) {
		memcpy(session->sessionKeyEnc, sessionKeyEnc, SESSION_KEY_LEN);
	} else if(sessionKeyRaw) {
		byte_t buf[SHA256_DIGEST_LENGTH];
		SHA256(sessionKeyRaw, SESSION_KEY_LEN, buf);
		memcpy(session->sessionKeyEnc, buf, SESSION_KEY_LEN);
	} else {
		FREE(&session->sessionKeyEnc);
	}

	session->userID = userID;
	session->mode = mode_trusted;
	session->username = username ? strdup(username) : NULL;
	session->refcount = 1;
	return session;
}
Пример #2
0
static int listener0(void *ctx, HTTPServerRef const server, HTTPConnectionRef const conn) {
	HTTPMethod method;
	str_t URI[URI_MAX];
	ssize_t len = HTTPConnectionReadRequest(conn, &method, URI, sizeof(URI));
	if(UV_EOF == len) {
		// HACK: Force the connection to realize it's dead.
		// Otherwise there is a timeout period of like 15-20 seconds
		// and we can run out of file descriptors. I suspect this
		// is a bug with libuv, but I'm not sure.
		HTTPConnectionWrite(conn, (byte_t const *)STR_LEN("x"));
		HTTPConnectionFlush(conn);
		return 0;
	}
	if(UV_EMSGSIZE == len) return 414; // Request-URI Too Large
	if(len < 0) {
		fprintf(stderr, "Request error: %s\n", uv_strerror(len));
		return 500;
	}

	HTTPHeadersRef headers;
	int rc = HTTPHeadersCreateFromConnection(conn, &headers);
	if(UV_EMSGSIZE == rc) return 431; // Request Header Fields Too Large
	if(rc < 0) return 500;

	strarg_t const host = HTTPHeadersGet(headers, "host");
	str_t domain[1023+1]; domain[0] = '\0';
	if(host) sscanf(host, "%1023[^:]", domain);
	// TODO: Verify Host header to prevent DNS rebinding.

	if(SERVER_PORT_TLS && server == server_raw) {
		// Redirect from HTTP to HTTPS
		if('\0' == domain[0]) return 400;
		strarg_t const port = SERVER_PORT_TLS;
		str_t loc[URI_MAX];
		rc = snprintf(loc, sizeof(loc), "https://%s:%s%s", domain, port, URI);
		if(rc >= sizeof(loc)) 414; // Request-URI Too Large
		if(rc < 0) return 500;
		HTTPConnectionSendRedirect(conn, 301, loc);
		return 0;
	}

	strarg_t const cookie = HTTPHeadersGet(headers, "cookie");
	SLNSessionCacheRef const cache = SLNRepoGetSessionCache(repo);
	SLNSessionRef session = NULL;
	rc = SLNSessionCacheCopyActiveSession(cache, cookie, &session);
	if(rc < 0) return 500;
	// Note: null session is valid (zero permissions).

	rc = -1;
	rc = rc >= 0 ? rc : SLNServerDispatch(repo, session, conn, method, URI, headers);
	rc = rc >= 0 ? rc : BlogDispatch(blog, session, conn, method, URI, headers);

	SLNSessionRelease(&session);
	HTTPHeadersFree(&headers);
	return rc;
}
Пример #3
0
static int POST_auth(BlogRef const blog, SLNSessionRef const session, HTTPConnectionRef const conn, HTTPMethod const method, strarg_t const URI, HTTPHeadersRef const headers) {
	if(HTTP_POST != method) return -1;
	if(0 != uripathcmp("/auth", URI, NULL)) return -1;

	// TODO: Check that Content-Type is application/x-www-form-urlencoded.

	str_t formdata[AUTH_FORM_MAX];
	ssize_t len = HTTPConnectionReadBodyStatic(conn, (byte_t *)formdata, sizeof(formdata)-1);
	if(UV_EMSGSIZE == len) return 413; // Request Entity Too Large
	if(len < 0) return 500;
	formdata[len] = '\0';

	SLNSessionCacheRef const cache = SLNRepoGetSessionCache(blog->repo);
	static strarg_t const fields[] = {
		"action-login",
		"action-register",
		"user",
		"pass",
		"token", // TODO: CSRF protection
	};
	str_t *values[numberof(fields)] = {};
	QSValuesParse(formdata, values, fields, numberof(fields));
	if(values[1]) {
		QSValuesCleanup(values, numberof(values));
		return 501; // TODO: Not Implemented
	}
	if(!values[0]) {
		QSValuesCleanup(values, numberof(values));
		return 400; // Not login?
	}
	SLNSessionRef s;
	int rc = SLNSessionCacheCreateSession(cache, values[2], values[3], &s); // TODO
	QSValuesCleanup(values, numberof(values));

	if(rc < 0) {
		HTTPConnectionSendRedirect(conn, 303, "/account?err=1");
		return 0;
	}

	str_t *cookie = SLNSessionCopyCookie(s);
	SLNSessionRelease(&s);
	if(!cookie) return 500;

	HTTPConnectionWriteResponse(conn, 303, "See Other");
	HTTPConnectionWriteHeader(conn, "Location", "/");
	HTTPConnectionWriteSetCookie(conn, cookie, "/", 60 * 60 * 24 * 365);
	HTTPConnectionWriteContentLength(conn, 0);
	HTTPConnectionBeginBody(conn);
	HTTPConnectionEnd(conn);

	FREE(&cookie);
	return 0;
}
Пример #4
0
int SLNSessionCreateSession(SLNSessionRef const session, SLNSessionRef *const out) {
	assert(out);
	if(!session) return DB_EACCES;

	SLNSessionCacheRef const cache = session->cache;
	uint64_t const userID = session->userID;
	SLNMode const mode = session->mode;
	strarg_t const username = session->username;
	DB_env *db = NULL;
	DB_txn *txn = NULL;
	SLNSessionRef alt = NULL;

	byte_t key_raw[SESSION_KEY_LEN];
	int rc = async_random(key_raw, sizeof(key_raw));
	if(rc < 0) goto cleanup;

	byte_t key_enc[SHA256_DIGEST_LENGTH];
	SHA256(key_raw, sizeof(key_raw), key_enc);

	str_t key_str[SESSION_KEY_HEX+1];
	tohex(key_str, key_enc, SESSION_KEY_LEN);
	key_str[SESSION_KEY_HEX] = '\0';

	rc = SLNSessionDBOpen(session, SLN_RDWR, &db); // TODO: Custom permission?
	if(rc < 0) goto cleanup;
	rc = db_txn_begin(db, NULL, DB_RDWR, &txn);
	if(rc < 0) goto cleanup;

	uint64_t const sessionID = db_next_id(SLNSessionByID, txn);
	DB_val key[1], val[1];
	SLNSessionByIDKeyPack(key, txn, sessionID);
	SLNSessionByIDValPack(val, txn, userID, key_str);
	rc = db_put(txn, key, val, DB_NOOVERWRITE_FAST);
	if(rc < 0) goto cleanup;

	rc = db_txn_commit(txn); txn = NULL;
	SLNSessionDBClose(session, &db);
	if(rc < 0) goto cleanup;

	rc = SLNSessionCreateInternal(cache, sessionID, key_raw, key_enc, userID, mode, username, &alt);
	if(rc < 0) goto cleanup;

	*out = alt; alt = NULL;

cleanup:
	db_txn_abort(txn); txn = NULL;
	SLNSessionDBClose(session, &db);
	SLNSessionRelease(&alt);
	return rc;
}
Пример #5
0
static int listener0(void *ctx, HTTPServerRef const server, HTTPConnectionRef const conn) {
    HTTPMethod method;
    str_t URI[URI_MAX];
    ssize_t len = HTTPConnectionReadRequest(conn, &method, URI, sizeof(URI));
    if(UV_EOF == len) return 0;
    if(UV_ECONNRESET == len) return 0;
    if(UV_EMSGSIZE == len) return 414; // Request-URI Too Large
    if(len < 0) {
        alogf("Request error: %s\n", uv_strerror(len));
        return 500;
    }

    HTTPHeadersRef headers;
    int rc = HTTPHeadersCreateFromConnection(conn, &headers);
    if(UV_EMSGSIZE == rc) return 431; // Request Header Fields Too Large
    if(rc < 0) return 500;

    strarg_t const host = HTTPHeadersGet(headers, "host");
    str_t domain[1023+1];
    domain[0] = '\0';
    if(host) sscanf(host, "%1023[^:]", domain);
    // TODO: Verify Host header to prevent DNS rebinding.

    if(SERVER_PORT_TLS && server == server_raw) {
        // Redirect from HTTP to HTTPS
        if('\0' == domain[0]) return 400;
        strarg_t const port = SERVER_PORT_TLS;
        str_t loc[URI_MAX];
        rc = snprintf(loc, sizeof(loc), "https://%s:%s%s", domain, port, URI);
        if(rc >= sizeof(loc)) 414; // Request-URI Too Large
        if(rc < 0) return 500;
        HTTPConnectionSendRedirect(conn, 301, loc);
        return 0;
    }

    strarg_t const cookie = HTTPHeadersGet(headers, "cookie");
    SLNSessionCacheRef const cache = SLNRepoGetSessionCache(repo);
    SLNSessionRef session = NULL;
    rc = SLNSessionCacheCopyActiveSession(cache, cookie, &session);
    if(rc < 0) return 500;
    // Note: null session is valid (zero permissions).

    rc = -1;
    rc = rc >= 0 ? rc : SLNServerDispatch(repo, session, conn, method, URI, headers);
    rc = rc >= 0 ? rc : BlogDispatch(blog, session, conn, method, URI, headers);

    SLNSessionRelease(&session);
    HTTPHeadersFree(&headers);
    return rc;
}
Пример #6
0
static void listener(void *ctx, HTTPServerRef const server, HTTPConnectionRef const conn) {
	assert(server);
	assert(conn);
	str_t URI[URI_MAX]; URI[0] = '\0';
	HTTPHeadersRef headers = NULL;
	SLNSessionRef session = NULL;
	int rc = listener0(server, conn, URI, sizeof(URI), &headers, &session);
	if(rc < 0) rc = 404;
	if(rc > 0) HTTPConnectionSendStatus(conn, rc);
	strarg_t const username = SLNSessionGetUsername(session);
	HTTPConnectionLog(conn, URI, username, headers, SERVER_LOG_FILE);
	SLNSessionRelease(&session);
	HTTPHeadersFree(&headers);
}
Пример #7
0
int SLNSessionCreateInternal(SLNSessionCacheRef const cache, uint64_t const sessionID, byte_t const *const sessionKeyRaw, byte_t const *const sessionKeyEnc, uint64_t const userID, SLNMode const mode_trusted, strarg_t const username, SLNSessionRef *const out) {
	assert(cache);
	assert(out);
	// 0 == sessionID is valid for "temporary" sessions.
	if(!mode_trusted) return UV_EACCES; // Even trusted code can't create a session without perms.

	SLNSessionRef session = calloc(1, sizeof(struct SLNSession));
	if(!session) return UV_ENOMEM;
	int rc = 0;

	session->refcount = 1;
	session->cache = cache;
	session->sessionID = sessionID;

	session->sessionKeyRaw = malloc(SESSION_KEY_LEN);
	session->sessionKeyEnc = malloc(SESSION_KEY_LEN);
	if(!session->sessionKeyRaw || !session->sessionKeyEnc) rc = UV_ENOMEM;
	if(rc < 0) goto cleanup;
	if(sessionKeyRaw) {
		memcpy(session->sessionKeyRaw, sessionKeyRaw, SESSION_KEY_LEN);
	} else {
		FREE(&session->sessionKeyRaw);
	}
	if(sessionKeyEnc) {
		memcpy(session->sessionKeyEnc, sessionKeyEnc, SESSION_KEY_LEN);
	} else if(sessionKeyRaw) {
		byte_t buf[SHA256_DIGEST_LENGTH];
		SHA256(sessionKeyRaw, SESSION_KEY_LEN, buf);
		memcpy(session->sessionKeyEnc, buf, SESSION_KEY_LEN);
	} else {
		FREE(&session->sessionKeyEnc);
	}

	session->userID = userID;
	session->mode = mode_trusted;
	session->username = username ? strdup(username) : NULL;

	*out = session; session = NULL;
cleanup:
	SLNSessionRelease(&session);
	return rc;
}
Пример #8
0
void SLNPullFree(SLNPullRef *const pullptr) {
	SLNPullRef pull = *pullptr;
	if(!pull) return;

	SLNPullStop(pull);

	pull->pullID = 0;
	SLNSessionRelease(&pull->session);
	FREE(&pull->host);
	FREE(&pull->cookie);
//	FREE(&pull->query);

	async_mutex_destroy(pull->connlock);
	async_mutex_destroy(pull->mutex);
	async_cond_destroy(pull->cond);
	pull->stop = false;

	assert_zeroed(pull, 1);
	FREE(pullptr); pull = NULL;
}