Commit | Line | Data |
---|---|---|
460b9539 | 1 | /* |
2 | * This file is part of DisOrder. | |
ac169f8a | 3 | * Copyright (C) 2004, 2005, 2007, 2008 Richard Kettlewell |
460b9539 | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 2 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, write to the Free Software | |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | |
18 | * USA | |
19 | */ | |
9faa7a88 RK |
20 | /** @file server/cgimain.c |
21 | * @brief DisOrder CGI | |
22 | */ | |
460b9539 | 23 | |
24 | #include <config.h> | |
6d2d327c | 25 | #include "types.h" |
460b9539 | 26 | |
27 | #include <stdio.h> | |
28 | #include <errno.h> | |
29 | #include <stdlib.h> | |
30 | #include <sys/types.h> | |
31 | #include <sys/socket.h> | |
32 | #include <locale.h> | |
33 | #include <string.h> | |
34 | #include <stdarg.h> | |
35 | ||
36 | #include "client.h" | |
37 | #include "sink.h" | |
9faa7a88 | 38 | #include "server-cgi.h" |
460b9539 | 39 | #include "mem.h" |
40 | #include "log.h" | |
41 | #include "configuration.h" | |
42 | #include "disorder.h" | |
43 | #include "api-client.h" | |
fdf98378 | 44 | #include "mime.h" |
b64c2805 | 45 | #include "printf.h" |
938d8157 | 46 | #include "dcgi.h" |
36bde473 | 47 | #include "url.h" |
fdf98378 | 48 | |
9faa7a88 RK |
49 | #include "macros.h" |
50 | #include "macros-disorder.h" | |
51 | ||
ac169f8a | 52 | /** @brief Return true if @p a is better than @p b |
53 | * | |
54 | * NB. We don't bother checking if the path is right, we merely check for the | |
55 | * longest path. This isn't a security hole: if the browser wants to send us | |
56 | * bad cookies it's quite capable of sending just the right path anyway. The | |
57 | * point of choosing the longest path is to avoid using a cookie set by another | |
58 | * CGI script which shares a path prefix with us, which would allow it to | |
59 | * maliciously log users out. | |
60 | * | |
61 | * Such a script could still "maliciously" log someone in, if it had acquired a | |
62 | * suitable cookie. But it could just log in directly if it had that, so there | |
63 | * is no obvious vulnerability here either. | |
64 | */ | |
65 | static int better_cookie(const struct cookie *a, const struct cookie *b) { | |
66 | if(a->path && b->path) | |
67 | /* If both have a path then the one with the longest path is best */ | |
68 | return strlen(a->path) > strlen(b->path); | |
69 | else if(a->path) | |
70 | /* If only @p a has a path then it is better */ | |
71 | return 1; | |
72 | else | |
73 | /* If neither have a path, or if only @p b has a path, then @p b is | |
74 | * better */ | |
75 | return 0; | |
76 | } | |
77 | ||
460b9539 | 78 | int main(int argc, char **argv) { |
fdf98378 | 79 | const char *cookie_env, *conf; |
460b9539 | 80 | dcgi_global g; |
81 | dcgi_state s; | |
82 | cgi_sink output; | |
ac169f8a | 83 | int n, best_cookie; |
fdf98378 | 84 | struct cookiedata cd; |
460b9539 | 85 | |
9faa7a88 RK |
86 | if(argc > 0) |
87 | progname = argv[0]; | |
ad9bae0b | 88 | /* RFC 3875 s8.2 recommends rejecting PATH_INFO if we don't make use of |
89 | * it. */ | |
90 | if(getenv("PATH_INFO")) { | |
9faa7a88 | 91 | /* TODO it might be nice to link back to the right place... */ |
ad9bae0b | 92 | printf("Content-Type: text/html\n"); |
93 | printf("Status: 404\n"); | |
94 | printf("\n"); | |
95 | printf("<p>Sorry, PATH_INFO not supported.</p>\n"); | |
96 | exit(0); | |
97 | } | |
460b9539 | 98 | cgi_parse(); |
9faa7a88 RK |
99 | /* We allow various things to be overridden from the environment. This is |
100 | * intended for debugging and is not a documented feature. */ | |
101 | if((conf = getenv("DISORDER_CONFIG"))) | |
102 | configfile = xstrdup(conf); | |
103 | if(getenv("DISORDER_DEBUG")) | |
104 | debugging = 1; | |
105 | if(config_read(0)) | |
106 | exit(EXIT_FAILURE); | |
107 | /* Figure out our URL. This can still be overridden from the config file if | |
108 | * necessary but it shouldn't be necessary in ordinary installations. */ | |
36bde473 | 109 | if(!config->url) |
110 | config->url = infer_url(); | |
460b9539 | 111 | memset(&g, 0, sizeof g); |
112 | memset(&s, 0, sizeof s); | |
113 | s.g = &g; | |
114 | g.client = disorder_get_client(); | |
115 | output.quote = 1; | |
b64c2805 | 116 | output.sink = sink_stdio("stdout", stdout); |
fdf98378 | 117 | /* See if there's a cookie */ |
118 | cookie_env = getenv("HTTP_COOKIE"); | |
119 | if(cookie_env) { | |
120 | /* This will be an HTTP header */ | |
121 | if(!parse_cookie(cookie_env, &cd)) { | |
ac169f8a | 122 | /* Pick the best available cookie from all those offered */ |
123 | best_cookie = -1; | |
124 | for(n = 0; n < cd.ncookies; ++n) { | |
125 | /* Is this the right cookie? */ | |
126 | if(strcmp(cd.cookies[n].name, "disorder")) | |
127 | continue; | |
128 | /* Is it better than anything we've seen so far? */ | |
129 | if(best_cookie < 0 | |
130 | || better_cookie(&cd.cookies[n], &cd.cookies[best_cookie])) | |
131 | best_cookie = n; | |
132 | } | |
133 | if(best_cookie != -1) | |
134 | login_cookie = cd.cookies[best_cookie].value; | |
06819653 | 135 | } else |
136 | error(0, "could not parse cookie field '%s'", cookie_env); | |
460b9539 | 137 | } |
9faa7a88 RK |
138 | /* Register expansions */ |
139 | mx_register_builtin(); | |
140 | register_disorder_expansions(); | |
141 | /* Update search path. We look in the config directory first and the data | |
142 | * directory second, so that the latter overrides the former. */ | |
143 | mx_search_path(pkgconfdir); | |
144 | mx_search_path(pkgdatadir); | |
145 | /* Create the initial connection, trying the cookie if we found a suitable | |
146 | * one. */ | |
938d8157 | 147 | disorder_cgi_login(&s, &output); |
9faa7a88 | 148 | /* The main program... */ |
460b9539 | 149 | disorder_cgi(&output, &s); |
9faa7a88 RK |
150 | /* In practice if a write fails that probably means the web server went away, |
151 | * but we log it anyway. */ | |
152 | if(fclose(stdout) < 0) | |
153 | fatal(errno, "error closing stdout"); | |
460b9539 | 154 | return 0; |
155 | } | |
156 | ||
157 | /* | |
158 | Local Variables: | |
159 | c-basic-offset:2 | |
160 | comment-column:40 | |
ac169f8a | 161 | fill-column:79 |
162 | indent-tabs-mode:nil | |
460b9539 | 163 | End: |
164 | */ |