chiark / gitweb /
Switch to GPL v3
[disorder] / cgi / login.c
CommitLineData
1e97629d
RK
1/*
2 * This file is part of DisOrder.
3 * Copyright (C) 2008 Richard Kettlewell
4 *
e7eb3a27 5 * This program is free software: you can redistribute it and/or modify
1e97629d 6 * it under the terms of the GNU General Public License as published by
e7eb3a27 7 * the Free Software Foundation, either version 3 of the License, or
1e97629d
RK
8 * (at your option) any later version.
9 *
e7eb3a27
RK
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
1e97629d 15 * You should have received a copy of the GNU General Public License
e7eb3a27 16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1e97629d
RK
17 */
18
19#include "disorder-cgi.h"
20
21/** @brief Client used by CGI
22 *
23 * The caller should arrange for this to be created before any of
24 * these expansions are used (if it cannot connect then it's safe to
25 * leave it as NULL).
26 */
27disorder_client *dcgi_client;
28
d0b6635e
RK
29/** @brief Return true if @p a is better than @p b
30 *
31 * NB. We don't bother checking if the path is right, we merely check for the
32 * longest path. This isn't a security hole: if the browser wants to send us
33 * bad cookies it's quite capable of sending just the right path anyway. The
34 * point of choosing the longest path is to avoid using a cookie set by another
35 * CGI script which shares a path prefix with us, which would allow it to
36 * maliciously log users out.
37 *
38 * Such a script could still "maliciously" log someone in, if it had acquired a
39 * suitable cookie. But it could just log in directly if it had that, so there
40 * is no obvious vulnerability here either.
41 */
42static int better_cookie(const struct cookie *a, const struct cookie *b) {
43 if(a->path && b->path)
44 /* If both have a path then the one with the longest path is best */
45 return strlen(a->path) > strlen(b->path);
46 else if(a->path)
47 /* If only @p a has a path then it is better */
48 return 1;
49 else
50 /* If neither have a path, or if only @p b has a path, then @p b is
51 * better */
52 return 0;
53}
54
1e97629d
RK
55/** @brief Login cookie */
56char *dcgi_cookie;
57
d0b6635e
RK
58/** @brief Set @ref login_cookie */
59void dcgi_get_cookie(void) {
60 const char *cookie_env;
61 int n, best_cookie;
62 struct cookiedata cd;
63
64 /* See if there's a cookie */
65 cookie_env = getenv("HTTP_COOKIE");
66 if(cookie_env) {
67 /* This will be an HTTP header */
68 if(!parse_cookie(cookie_env, &cd)) {
69 /* Pick the best available cookie from all those offered */
70 best_cookie = -1;
71 for(n = 0; n < cd.ncookies; ++n) {
72 /* Is this the right cookie? */
73 if(strcmp(cd.cookies[n].name, "disorder"))
74 continue;
75 /* Is it better than anything we've seen so far? */
76 if(best_cookie < 0
77 || better_cookie(&cd.cookies[n], &cd.cookies[best_cookie]))
78 best_cookie = n;
79 }
80 if(best_cookie != -1)
81 dcgi_cookie = cd.cookies[best_cookie].value;
82 } else
83 error(0, "could not parse cookie field '%s'", cookie_env);
84 }
85}
86
1e97629d
RK
87/** @brief Return a Cookie: header */
88char *dcgi_cookie_header(void) {
89 struct dynstr d[1];
90 struct url u;
91 char *s;
92
93 memset(&u, 0, sizeof u);
94 dynstr_init(d);
95 parse_url(config->url, &u);
96 if(dcgi_cookie) {
97 dynstr_append_string(d, "disorder=");
98 dynstr_append_string(d, dcgi_cookie);
99 } else {
100 /* Force browser to discard cookie */
101 dynstr_append_string(d, "disorder=none;Max-Age=0");
102 }
103 if(u.path) {
104 /* The default domain matches the request host, so we need not override
105 * that. But the default path only goes up to the rightmost /, which would
106 * cause the browser to expose the cookie to other CGI programs on the same
107 * web server. */
108 dynstr_append_string(d, ";Version=1;Path=");
109 /* Formally we are supposed to quote the path, since it invariably has a
110 * slash in it. However Safari does not parse quoted paths correctly, so
111 * this won't work. Fortunately nothing else seems to care about proper
112 * quoting of paths, so in practice we get with it. (See also
113 * parse_cookie() where we are liberal about cookie paths on the way back
114 * in.) */
115 dynstr_append_string(d, u.path);
116 }
117 dynstr_terminate(d);
118 byte_xasprintf(&s, "Set-Cookie: %s", d->vec);
119 return s;
120}
121
122/** @brief Log in as the current user or guest if none */
123void dcgi_login(void) {
124 /* Junk old data */
125 dcgi_lookup_reset();
126 /* Junk the old connection if there is one */
127 if(dcgi_client)
128 disorder_close(dcgi_client);
129 /* Create a new connection */
130 dcgi_client = disorder_new(0);
131 /* Reconnect */
132 if(disorder_connect_cookie(dcgi_client, dcgi_cookie)) {
0d0253c9 133 dcgi_error("connect");
1e97629d
RK
134 exit(0);
135 }
136 /* If there was a cookie but it went bad, we forget it */
137 if(dcgi_cookie && !strcmp(disorder_user(dcgi_client), "guest"))
138 dcgi_cookie = 0;
139}
140
141/*
142Local Variables:
143c-basic-offset:2
144comment-column:40
145fill-column:79
146indent-tabs-mode:nil
147End:
148*/