kore/src/auth.c

174 lines
3.8 KiB
C

/*
* Copyright (c) 2014 Joris Vink <joris@coders.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/param.h>
#include <sys/types.h>
#include <ctype.h>
#include "kore.h"
#include "http.h"
TAILQ_HEAD(, kore_auth) auth_list;
void
kore_auth_init(void)
{
TAILQ_INIT(&auth_list);
}
int
kore_auth_new(const char *name)
{
struct kore_auth *auth;
if (kore_auth_lookup(name) != NULL)
return (KORE_RESULT_ERROR);
auth = kore_malloc(sizeof(*auth));
auth->type = 0;
auth->value = NULL;
auth->redirect = NULL;
auth->validator = NULL;
auth->name = kore_strdup(name);
TAILQ_INSERT_TAIL(&auth_list, auth, list);
return (KORE_RESULT_OK);
}
int
kore_auth_run(struct http_request *req, struct kore_auth *auth)
{
int r;
switch (auth->type) {
case KORE_AUTH_TYPE_COOKIE:
r = kore_auth_cookie(req, auth);
break;
case KORE_AUTH_TYPE_HEADER:
r = kore_auth_header(req, auth);
break;
case KORE_AUTH_TYPE_REQUEST:
r = kore_auth_request(req, auth);
break;
default:
kore_log(LOG_NOTICE, "unknown auth type %d", auth->type);
return (KORE_RESULT_ERROR);
}
switch (r) {
case KORE_RESULT_OK:
req->flags |= HTTP_REQUEST_AUTHED;
/* FALLTHROUGH */
case KORE_RESULT_RETRY:
return (r);
default:
break;
}
/* Authentication types of "request" send their own HTTP responses. */
if (auth->type == KORE_AUTH_TYPE_REQUEST)
return (r);
if (auth->redirect == NULL) {
http_response(req, HTTP_STATUS_FORBIDDEN, NULL, 0);
return (KORE_RESULT_ERROR);
}
http_response_header(req, "location", auth->redirect);
http_response(req, HTTP_STATUS_FOUND, NULL, 0);
return (KORE_RESULT_ERROR);
}
int
kore_auth_cookie(struct http_request *req, struct kore_auth *auth)
{
const char *hdr;
int i, v;
size_t len, slen;
char *value, *c, *cookie, *cookies[HTTP_MAX_COOKIES];
if (!http_request_header(req, "cookie", &hdr))
return (KORE_RESULT_ERROR);
cookie = kore_strdup(hdr);
slen = strlen(auth->value);
v = kore_split_string(cookie, ";", cookies, HTTP_MAX_COOKIES);
for (i = 0; i < v; i++) {
for (c = cookies[i]; isspace(*(unsigned char *)c); c++)
;
len = MIN(slen, strlen(cookies[i]));
if (!strncmp(c, auth->value, len))
break;
}
if (i == v) {
kore_free(cookie);
return (KORE_RESULT_ERROR);
}
c = cookies[i];
if ((value = strchr(c, '=')) == NULL) {
kore_free(cookie);
return (KORE_RESULT_ERROR);
}
i = kore_validator_check(req, auth->validator, ++value);
kore_free(cookie);
return (i);
}
int
kore_auth_header(struct http_request *req, struct kore_auth *auth)
{
const char *header;
if (!http_request_header(req, auth->value, &header))
return (KORE_RESULT_ERROR);
return (kore_validator_check(req, auth->validator, header));
}
int
kore_auth_request(struct http_request *req, struct kore_auth *auth)
{
int ret;
req->flags |= HTTP_VALIDATOR_IS_REQUEST;
ret = kore_validator_check(req, auth->validator, req);
req->flags &= ~HTTP_VALIDATOR_IS_REQUEST;
return (ret);
}
struct kore_auth *
kore_auth_lookup(const char *name)
{
struct kore_auth *auth;
TAILQ_FOREACH(auth, &auth_list, list) {
if (!strcmp(auth->name, name))
return (auth);
}
return (NULL);
}