auth.c (3845B)
1 /*
2 * Copyright (c) 2014 Joris Vink <joris@coders.se>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <sys/param.h>
18 #include <sys/types.h>
19
20 #include <ctype.h>
21
22 #include "kore.h"
23 #include "http.h"
24
25 TAILQ_HEAD(, kore_auth) auth_list;
26
27 void
28 kore_auth_init(void)
29 {
30 TAILQ_INIT(&auth_list);
31 }
32
33 int
34 kore_auth_new(const char *name)
35 {
36 struct kore_auth *auth;
37
38 if (kore_auth_lookup(name) != NULL)
39 return (KORE_RESULT_ERROR);
40
41 auth = kore_malloc(sizeof(*auth));
42 auth->type = 0;
43 auth->value = NULL;
44 auth->redirect = NULL;
45 auth->validator = NULL;
46 auth->name = kore_strdup(name);
47
48 TAILQ_INSERT_TAIL(&auth_list, auth, list);
49
50 return (KORE_RESULT_OK);
51 }
52
53 int
54 kore_auth_run(struct http_request *req, struct kore_auth *auth)
55 {
56 int r;
57
58 switch (auth->type) {
59 case KORE_AUTH_TYPE_COOKIE:
60 r = kore_auth_cookie(req, auth);
61 break;
62 case KORE_AUTH_TYPE_HEADER:
63 r = kore_auth_header(req, auth);
64 break;
65 case KORE_AUTH_TYPE_REQUEST:
66 r = kore_auth_request(req, auth);
67 break;
68 default:
69 kore_log(LOG_NOTICE, "unknown auth type %d", auth->type);
70 return (KORE_RESULT_ERROR);
71 }
72
73 switch (r) {
74 case KORE_RESULT_OK:
75 req->flags |= HTTP_REQUEST_AUTHED;
76 /* FALLTHROUGH */
77 case KORE_RESULT_RETRY:
78 return (r);
79 default:
80 break;
81 }
82
83 /* Authentication types of "request" send their own HTTP responses. */
84 if (auth->type == KORE_AUTH_TYPE_REQUEST)
85 return (r);
86
87 if (auth->redirect == NULL) {
88 http_response(req, HTTP_STATUS_FORBIDDEN, NULL, 0);
89 return (KORE_RESULT_ERROR);
90 }
91
92 http_response_header(req, "location", auth->redirect);
93 http_response(req, HTTP_STATUS_FOUND, NULL, 0);
94
95 return (KORE_RESULT_ERROR);
96 }
97
98 int
99 kore_auth_cookie(struct http_request *req, struct kore_auth *auth)
100 {
101 const char *hdr;
102 int i, v;
103 size_t len, slen;
104 char *value, *c, *cookie, *cookies[HTTP_MAX_COOKIES];
105
106 if (!http_request_header(req, "cookie", &hdr))
107 return (KORE_RESULT_ERROR);
108
109 cookie = kore_strdup(hdr);
110
111 slen = strlen(auth->value);
112 v = kore_split_string(cookie, ";", cookies, HTTP_MAX_COOKIES);
113 for (i = 0; i < v; i++) {
114 for (c = cookies[i]; isspace(*(unsigned char *)c); c++)
115 ;
116
117 len = MIN(slen, strlen(cookies[i]));
118 if (!strncmp(c, auth->value, len))
119 break;
120 }
121
122 if (i == v) {
123 kore_free(cookie);
124 return (KORE_RESULT_ERROR);
125 }
126
127 c = cookies[i];
128 if ((value = strchr(c, '=')) == NULL) {
129 kore_free(cookie);
130 return (KORE_RESULT_ERROR);
131 }
132
133 i = kore_validator_check(req, auth->validator, ++value);
134 kore_free(cookie);
135
136 return (i);
137 }
138
139 int
140 kore_auth_header(struct http_request *req, struct kore_auth *auth)
141 {
142 const char *header;
143
144 if (!http_request_header(req, auth->value, &header))
145 return (KORE_RESULT_ERROR);
146
147 return (kore_validator_check(req, auth->validator, header));
148 }
149
150 int
151 kore_auth_request(struct http_request *req, struct kore_auth *auth)
152 {
153 int ret;
154
155 req->flags |= HTTP_VALIDATOR_IS_REQUEST;
156 ret = kore_validator_check(req, auth->validator, req);
157 req->flags &= ~HTTP_VALIDATOR_IS_REQUEST;
158
159 return (ret);
160 }
161
162 struct kore_auth *
163 kore_auth_lookup(const char *name)
164 {
165 struct kore_auth *auth;
166
167 TAILQ_FOREACH(auth, &auth_list, list) {
168 if (!strcmp(auth->name, name))
169 return (auth);
170 }
171
172 return (NULL);
173 }