1 /*
2  *
3  * cgi.c -
4  *
5  * Copyright (C) 1997-1999 Satoru Takabayashi  All rights reserved.
6  * This is free software with ABSOLUTELY NO WARRANTY.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21  * 02111-1307, USA
22  *
23  * This file must be encoded in EUC-JP encoding.
24  *
25  */
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <ctype.h>
31 #include "namazu.h"
32 #include "util.h"
33 
34 uchar *ScriptName = "", *QueryString = "", *ContentLength = "";
35 
36 /* validate dbname (if it contain '/', it's invalid) */
validate_dbname(uchar * dbname)37 int validate_dbname(uchar * dbname)
38 {
39     int win32 = 0;
40 #if  defined(WIN32) || defined(OS2)
41     win32 = 1;
42 #endif
43 
44     if (*dbname == '\0' || *dbname == '/' || (win32 && *dbname == '\\')) {
45         fputs(MSG_MIME_HEADER, stdout);
46         fputx(MSG_INVALID_DB_NAME, stdout);
47         exit(1);
48     }
49     while (*dbname) {
50         if (strncmp("../", dbname, 3) == 0 ||
51 	    strcmp("..", dbname) == 0 ||
52             (win32 && strncmp("..\\", dbname, 3) == 0))
53         {
54             fputs(MSG_MIME_HEADER, stdout);
55             fputx(MSG_INVALID_DB_NAME, stdout);
56             exit(1);
57         }
58 	/* Skip until next '/' */
59 	while (*dbname && *dbname != '/' && !(win32 && *dbname == '\\'))
60 	  dbname++;
61 	/* Skip '/' */
62 	if (*dbname)
63 	  dbname++;
64     }
65     dbname--;  /* remove ending slashed */
66     while (*dbname == '/' || (win32 && *dbname == '\\')) {
67         *dbname = '\0';
68         dbname--;
69     }
70     return 1;
71 }
72 
73 
74 /*  get CGI variables, very complicated routine */
get_cgi_variables(uchar * query,uchar * subquery)75 int get_cgi_variables(uchar * query, uchar *subquery)
76 {
77     int i;
78     uchar *qs, tmp[BUFSIZE];
79     int content_length;
80 
81     if ((QueryString = getenv("QUERY_STRING"))) {
82         content_length = strlen(QueryString);
83         if (content_length > QUERY_STRING_MAX_LENGTH) {
84             fputs(MSG_MIME_HEADER, stdout);
85             fputx(MSG_QUERY_STRING_TOO_LONG, stdout);
86             exit(1);
87         }
88         if (!(ScriptName = getenv("SCRIPT_NAME"))) {
89             return 1;
90         }
91     } else {
92 	if ((ContentLength = getenv("CONTENT_LENGTH"))) {
93 	    content_length = atoi(ContentLength);
94             if (content_length > QUERY_STRING_MAX_LENGTH) {
95                 fputs(MSG_MIME_HEADER, stdout);
96                 fputx(MSG_QUERY_STRING_TOO_LONG, stdout);
97                 exit(1);
98             }
99             QueryString = (uchar *)malloc(content_length * sizeof(uchar) + 1);
100 	    if (QueryString == NULL)
101 		error("QueryString( get_cgi_variables )");
102 
103 	    fread(QueryString, sizeof(char), content_length, stdin);
104 	    HtmlOutput = 1;
105 	    HidePageIndex = 1;
106 	} else {
107 	    return 1;
108 	}
109     }
110     qs = QueryString;
111     DbNumber = 0;
112 
113     /* note that CERN HTTPD would add empty PATH_INFO */
114     if (getenv("PATH_INFO")) {
115         char *path_info = getenv("PATH_INFO");
116         if (strlen(path_info) > 0 && strlen(path_info) < 128) {
117             validate_dbname(path_info);
118             sprintf(tmp, "%s%s", DEFAULT_DIR, path_info);
119             DbNames[DbNumber] = (uchar *) malloc(strlen(tmp) + 1);
120             if (DbNames[DbNumber] == NULL) {
121                 error("cgi: malloc(dbname)");
122             }
123             strcpy(DbNames[DbNumber], tmp);
124             DbNumber++;
125         }
126     }
127 
128     while (*qs) {
129         if (*qs == '&') {
130             qs++;
131             continue;
132         } else if (!strncmp(qs, "key=", 4)) {
133 	    qs += 4;
134 
135 	    for (i = 0; *qs && *qs != '&'; qs++, i++) {
136                 *(query + i) = *qs;
137 	    }
138 	    *(query + i) = '\0';
139             decode_url_string(query);
140 	    if (strlen(query) > QUERY_MAX_LENGTH) {
141                 fputs(MSG_MIME_HEADER, stdout);
142 		fputx(MSG_TOO_LONG_KEY, stdout);
143 		exit(1);
144 	    }
145 
146 #ifdef MSIE4MACFIX
147 #define MSIE4MAC "Mozilla/4.0 (compatible; MSIE 4.01; Mac"
148 
149             if (!strncmp(query, "%1B", 3)) {
150                 char *agent = getenv("HTTP_USER_AGENT");
151                 if (agent && !strncmp(agent, MSIE4MAC, strlen(MSIE4MAC))) {
152                     decode_url_string(query);
153                 }
154             }
155 #endif MSIE4MACFIX
156 
157 	} else if (!strncmp(qs, "subquery=", 4)) {
158 	    qs += 9;
159 
160 	    for (i = 0; *qs && *qs != '&'; qs++, i++) {
161                 *(subquery + i) = *qs;
162 	    }
163 	    *(subquery + i) = '\0';
164             decode_url_string(subquery);
165 	    if (strlen(subquery) > QUERY_MAX_LENGTH) {
166                 fputs(MSG_MIME_HEADER, stdout);
167 		fputx(MSG_TOO_LONG_KEY, stdout);
168 		exit(1);
169 	    }
170 
171 #ifdef MSIE4MACFIX
172 #define MSIE4MAC "Mozilla/4.0 (compatible; MSIE 4.01; Mac"
173 
174             if (!strncmp(subquery, "%1B", 3)) {
175                 char *agent = getenv("HTTP_USER_AGENT");
176                 if (agent && !strncmp(agent, MSIE4MAC, strlen(MSIE4MAC))) {
177                     decode_url_string(subquery);
178                 }
179             }
180 #endif MSIE4MACFIX
181 
182 	} else if (!strncmp(qs, "format=short", 12)) {
183 	    ShortFormat = 1;
184 	    qs += 12;
185 	} else if (!strncmp(qs, "sort=", 5)) {
186 	    qs += 5;
187 	    if (!strncmp(qs, "score", 5)) {
188 		ScoreSort = 1;
189 		qs += 5;
190 	    } else if (!strncmp(qs, "later", 5)) {
191 		LaterOrder = 1;
192 		ScoreSort = 0;
193 		qs += 5;
194 	    } else if (!strncmp(qs, "earlier", 7)) {
195 		LaterOrder = 0;
196 		ScoreSort = 0;
197 		qs += 7;
198 	    }
199 	    while (*qs && *qs != '&')
200 		qs++;
201 	} else if (!strncmp(qs, "max=", 4)) {
202 	    qs += 4;
203 	    sscanf(qs, "%d", &HListMax);
204 	    if (HListMax < 0)
205 		HListMax = 0;
206 	    if (HListMax > HLIST_MAX_MAX)
207 		HListMax = HLIST_MAX_MAX;
208 	    while (*qs && *qs != '&')
209 		qs++;
210 	} else if (!strncmp(qs, "whence=", 7)) {
211 	    qs += 7;
212 	    sscanf(qs, "%d", &HListWhence);
213 	    if (HListWhence < 0)
214 		HListWhence = 0;
215 	    while (*qs && *qs != '&')
216 		qs++;
217 	} else if (!strncmp(qs, "lang=", 5)) {
218 	    qs += 5;
219             strncpy(Lang, qs, 2);
220             qs += 2;
221             initialize_message();
222 	    while (*qs && *qs != '&')
223 		qs++;
224 	} else if (!strncmp(qs, "reference=off", 13)) {
225             NoReference = 1;
226             qs += 13;
227 	} else if (!strncmp(qs, "mode=tknamazu", 13)) {
228             ModeTknamazu = 1;
229             qs += 13;
230 	} else if (!strncmp(qs, "dbname=", 7)) {
231             uchar *pp;
232 
233 	    qs += 7;
234 	    for (i = 0; *qs && *qs != '&' && i <= DBNAMELENG_MAX; i++, qs++)
235 		tmp[i] = *qs;
236             tmp[i] = '\0';
237             decode_url_string(tmp);
238             for (pp = tmp; *pp ;) {
239                 uchar name[BUFSIZE], *x;
240 
241                 if ((x = strchr(pp, (int)','))) {
242                     *x = '\0';
243                     strcpy(name, pp);
244                     pp = x + 1;
245                 } else {
246                     strcpy(name, pp);
247                     pp += strlen(pp);
248                 }
249                 if (DbNumber >= DB_MAX) { /* ignore too many indices */
250                     continue;
251                 }
252                 DbNames[DbNumber] = (uchar *)
253                     malloc(strlen(DEFAULT_DIR) + 1 + strlen(name) + 1);
254                 if (DbNames[DbNumber] == NULL) {
255                     error("cgi: malloc(dbname)");
256                 }
257                 validate_dbname(name);
258                 strcpy(DbNames[DbNumber], DEFAULT_DIR);
259                 strcat(DbNames[DbNumber], "/");
260                 strcat(DbNames[DbNumber], name);
261                 DbNumber++;
262             }
263 	    while (*qs && *qs != '&')
264 		qs++;
265 	} else {
266 	    qs++;
267         }
268     }
269     return 0;
270 }
271 
272 
273 /* initialize CGI mode. actually, to be invoked from commandline
274  * with no arguments also trhough this function */
cgi_initialize(uchar * query,uchar * subquery)275 void cgi_initialize(uchar * query, uchar *subquery)
276 {
277     if (get_cgi_variables(query, subquery))
278 	show_usage();	/* if it is NOT CGI, show usage usage */
279     if (DbNumber == 0) {
280         DbNames[DbNumber] = (uchar *) malloc(strlen(DEFAULT_DIR) + 1);
281         if (DbNames[DbNumber] == NULL) {
282             error("cgi_initialize: malloc(dbname)");
283         }
284         strcpy(DbNames[DbNumber], DEFAULT_DIR);
285         DbNumber++;
286     }
287 }
288 
289 /* decde URLencode */
290 /* c & 0xdf means to uppercase c */
URLdecode(uchar c,uchar c2)291 uchar URLdecode(uchar c, uchar c2)
292 {
293 
294     c = ((c >= 'A' ? ((c & 0xdf) - 'A') + 10 : (c - '0'))) * 16;
295     c += (c2 >= 'A' ? ((c2 & 0xdf) - 'A') + 10 : (c2 - '0'));
296     return c;
297 }
298 
299 
300 
301 
302