1*340f5e56SDavid van Moolenbroek /* $NetBSD: dir-index-bozo.c,v 1.21 2015/08/27 17:12:18 mrg Exp $ */
2*340f5e56SDavid van Moolenbroek
3*340f5e56SDavid van Moolenbroek /* $eterna: dir-index-bozo.c,v 1.20 2011/11/18 09:21:15 mrg Exp $ */
4*340f5e56SDavid van Moolenbroek
5*340f5e56SDavid van Moolenbroek /*
6*340f5e56SDavid van Moolenbroek * Copyright (c) 1997-2014 Matthew R. Green
7*340f5e56SDavid van Moolenbroek * All rights reserved.
8*340f5e56SDavid van Moolenbroek *
9*340f5e56SDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without
10*340f5e56SDavid van Moolenbroek * modification, are permitted provided that the following conditions
11*340f5e56SDavid van Moolenbroek * are met:
12*340f5e56SDavid van Moolenbroek * 1. Redistributions of source code must retain the above copyright
13*340f5e56SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer.
14*340f5e56SDavid van Moolenbroek * 2. Redistributions in binary form must reproduce the above copyright
15*340f5e56SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer and
16*340f5e56SDavid van Moolenbroek * dedication in the documentation and/or other materials provided
17*340f5e56SDavid van Moolenbroek * with the distribution.
18*340f5e56SDavid van Moolenbroek *
19*340f5e56SDavid van Moolenbroek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20*340f5e56SDavid van Moolenbroek * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21*340f5e56SDavid van Moolenbroek * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22*340f5e56SDavid van Moolenbroek * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23*340f5e56SDavid van Moolenbroek * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24*340f5e56SDavid van Moolenbroek * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25*340f5e56SDavid van Moolenbroek * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26*340f5e56SDavid van Moolenbroek * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27*340f5e56SDavid van Moolenbroek * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*340f5e56SDavid van Moolenbroek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*340f5e56SDavid van Moolenbroek * SUCH DAMAGE.
30*340f5e56SDavid van Moolenbroek *
31*340f5e56SDavid van Moolenbroek */
32*340f5e56SDavid van Moolenbroek
33*340f5e56SDavid van Moolenbroek /* this code implements directory index generation for bozohttpd */
34*340f5e56SDavid van Moolenbroek
35*340f5e56SDavid van Moolenbroek #ifndef NO_DIRINDEX_SUPPORT
36*340f5e56SDavid van Moolenbroek
37*340f5e56SDavid van Moolenbroek #include <sys/param.h>
38*340f5e56SDavid van Moolenbroek
39*340f5e56SDavid van Moolenbroek #include <dirent.h>
40*340f5e56SDavid van Moolenbroek #include <errno.h>
41*340f5e56SDavid van Moolenbroek #include <string.h>
42*340f5e56SDavid van Moolenbroek #include <stdlib.h>
43*340f5e56SDavid van Moolenbroek #include <time.h>
44*340f5e56SDavid van Moolenbroek #include <assert.h>
45*340f5e56SDavid van Moolenbroek
46*340f5e56SDavid van Moolenbroek #include "bozohttpd.h"
47*340f5e56SDavid van Moolenbroek
48*340f5e56SDavid van Moolenbroek static void
directory_hr(bozohttpd_t * httpd)49*340f5e56SDavid van Moolenbroek directory_hr(bozohttpd_t *httpd)
50*340f5e56SDavid van Moolenbroek {
51*340f5e56SDavid van Moolenbroek
52*340f5e56SDavid van Moolenbroek bozo_printf(httpd,
53*340f5e56SDavid van Moolenbroek "<hr noshade align=\"left\" width=\"80%%\">\r\n\r\n");
54*340f5e56SDavid van Moolenbroek }
55*340f5e56SDavid van Moolenbroek
56*340f5e56SDavid van Moolenbroek /*
57*340f5e56SDavid van Moolenbroek * output a directory index. return 1 if it actually did something..
58*340f5e56SDavid van Moolenbroek */
59*340f5e56SDavid van Moolenbroek int
bozo_dir_index(bozo_httpreq_t * request,const char * dirpath,int isindex)60*340f5e56SDavid van Moolenbroek bozo_dir_index(bozo_httpreq_t *request, const char *dirpath, int isindex)
61*340f5e56SDavid van Moolenbroek {
62*340f5e56SDavid van Moolenbroek bozohttpd_t *httpd = request->hr_httpd;
63*340f5e56SDavid van Moolenbroek struct stat sb;
64*340f5e56SDavid van Moolenbroek struct dirent **de, **deo;
65*340f5e56SDavid van Moolenbroek struct tm *tm;
66*340f5e56SDavid van Moolenbroek DIR *dp;
67*340f5e56SDavid van Moolenbroek char buf[MAXPATHLEN];
68*340f5e56SDavid van Moolenbroek char spacebuf[48];
69*340f5e56SDavid van Moolenbroek char *file = NULL;
70*340f5e56SDavid van Moolenbroek int l, k, j, i;
71*340f5e56SDavid van Moolenbroek
72*340f5e56SDavid van Moolenbroek if (!isindex || !httpd->dir_indexing)
73*340f5e56SDavid van Moolenbroek return 0;
74*340f5e56SDavid van Moolenbroek
75*340f5e56SDavid van Moolenbroek if (strlen(dirpath) <= strlen(httpd->index_html))
76*340f5e56SDavid van Moolenbroek dirpath = ".";
77*340f5e56SDavid van Moolenbroek else {
78*340f5e56SDavid van Moolenbroek file = bozostrdup(httpd, dirpath);
79*340f5e56SDavid van Moolenbroek
80*340f5e56SDavid van Moolenbroek file[strlen(file) - strlen(httpd->index_html)] = '\0';
81*340f5e56SDavid van Moolenbroek dirpath = file;
82*340f5e56SDavid van Moolenbroek }
83*340f5e56SDavid van Moolenbroek debug((httpd, DEBUG_FAT, "bozo_dir_index: dirpath ``%s''", dirpath));
84*340f5e56SDavid van Moolenbroek if (stat(dirpath, &sb) < 0 ||
85*340f5e56SDavid van Moolenbroek (dp = opendir(dirpath)) == NULL) {
86*340f5e56SDavid van Moolenbroek if (errno == EPERM)
87*340f5e56SDavid van Moolenbroek (void)bozo_http_error(httpd, 403, request,
88*340f5e56SDavid van Moolenbroek "no permission to open directory");
89*340f5e56SDavid van Moolenbroek else if (errno == ENOENT)
90*340f5e56SDavid van Moolenbroek (void)bozo_http_error(httpd, 404, request, "no file");
91*340f5e56SDavid van Moolenbroek else
92*340f5e56SDavid van Moolenbroek (void)bozo_http_error(httpd, 500, request,
93*340f5e56SDavid van Moolenbroek "open directory");
94*340f5e56SDavid van Moolenbroek goto done;
95*340f5e56SDavid van Moolenbroek /* NOTREACHED */
96*340f5e56SDavid van Moolenbroek }
97*340f5e56SDavid van Moolenbroek
98*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "%s 200 OK\r\n", request->hr_proto);
99*340f5e56SDavid van Moolenbroek
100*340f5e56SDavid van Moolenbroek if (request->hr_proto != httpd->consts.http_09) {
101*340f5e56SDavid van Moolenbroek bozo_print_header(request, NULL, "text/html", "");
102*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "\r\n");
103*340f5e56SDavid van Moolenbroek }
104*340f5e56SDavid van Moolenbroek bozo_flush(httpd, stdout);
105*340f5e56SDavid van Moolenbroek
106*340f5e56SDavid van Moolenbroek if (request->hr_method == HTTP_HEAD) {
107*340f5e56SDavid van Moolenbroek closedir(dp);
108*340f5e56SDavid van Moolenbroek goto done;
109*340f5e56SDavid van Moolenbroek }
110*340f5e56SDavid van Moolenbroek
111*340f5e56SDavid van Moolenbroek bozo_printf(httpd,
112*340f5e56SDavid van Moolenbroek "<html><head><title>Index of %s</title></head>\r\n",
113*340f5e56SDavid van Moolenbroek request->hr_file);
114*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "<body><h1>Index of %s</h1>\r\n",
115*340f5e56SDavid van Moolenbroek request->hr_file);
116*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "<pre>\r\n");
117*340f5e56SDavid van Moolenbroek #define NAMELEN 40
118*340f5e56SDavid van Moolenbroek #define LMODLEN 19
119*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "Name "
120*340f5e56SDavid van Moolenbroek "Last modified "
121*340f5e56SDavid van Moolenbroek "Size\n");
122*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "</pre>");
123*340f5e56SDavid van Moolenbroek directory_hr(httpd);
124*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "<pre>");
125*340f5e56SDavid van Moolenbroek
126*340f5e56SDavid van Moolenbroek for (j = k = scandir(dirpath, &de, NULL, alphasort), deo = de;
127*340f5e56SDavid van Moolenbroek j--; de++) {
128*340f5e56SDavid van Moolenbroek int nostat = 0;
129*340f5e56SDavid van Moolenbroek char *name = (*de)->d_name;
130*340f5e56SDavid van Moolenbroek char *urlname, *htmlname;
131*340f5e56SDavid van Moolenbroek
132*340f5e56SDavid van Moolenbroek if (strcmp(name, ".") == 0 ||
133*340f5e56SDavid van Moolenbroek (strcmp(name, "..") != 0 &&
134*340f5e56SDavid van Moolenbroek httpd->hide_dots && name[0] == '.'))
135*340f5e56SDavid van Moolenbroek continue;
136*340f5e56SDavid van Moolenbroek
137*340f5e56SDavid van Moolenbroek snprintf(buf, sizeof buf, "%s/%s", dirpath, name);
138*340f5e56SDavid van Moolenbroek if (stat(buf, &sb))
139*340f5e56SDavid van Moolenbroek nostat = 1;
140*340f5e56SDavid van Moolenbroek
141*340f5e56SDavid van Moolenbroek l = 0;
142*340f5e56SDavid van Moolenbroek
143*340f5e56SDavid van Moolenbroek urlname = bozo_escape_rfc3986(httpd, name);
144*340f5e56SDavid van Moolenbroek htmlname = bozo_escape_html(httpd, name);
145*340f5e56SDavid van Moolenbroek if (htmlname == NULL)
146*340f5e56SDavid van Moolenbroek htmlname = name;
147*340f5e56SDavid van Moolenbroek if (strcmp(name, "..") == 0) {
148*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "<a href=\"../\">");
149*340f5e56SDavid van Moolenbroek l += bozo_printf(httpd, "Parent Directory");
150*340f5e56SDavid van Moolenbroek } else if (S_ISDIR(sb.st_mode)) {
151*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "<a href=\"%s/\">", urlname);
152*340f5e56SDavid van Moolenbroek l += bozo_printf(httpd, "%s/", htmlname);
153*340f5e56SDavid van Moolenbroek } else if (strchr(name, ':') != NULL) {
154*340f5e56SDavid van Moolenbroek /* RFC 3986 4.2 */
155*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "<a href=\"./%s\">", urlname);
156*340f5e56SDavid van Moolenbroek l += bozo_printf(httpd, "%s", htmlname);
157*340f5e56SDavid van Moolenbroek } else {
158*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "<a href=\"%s\">", urlname);
159*340f5e56SDavid van Moolenbroek l += bozo_printf(httpd, "%s", htmlname);
160*340f5e56SDavid van Moolenbroek }
161*340f5e56SDavid van Moolenbroek if (htmlname != name)
162*340f5e56SDavid van Moolenbroek free(htmlname);
163*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "</a>");
164*340f5e56SDavid van Moolenbroek
165*340f5e56SDavid van Moolenbroek /* NAMELEN spaces */
166*340f5e56SDavid van Moolenbroek /*LINTED*/
167*340f5e56SDavid van Moolenbroek assert(/*CONSTCOND*/sizeof(spacebuf) > NAMELEN);
168*340f5e56SDavid van Moolenbroek i = (l < NAMELEN) ? (NAMELEN - l) : 0;
169*340f5e56SDavid van Moolenbroek i++;
170*340f5e56SDavid van Moolenbroek memset(spacebuf, ' ', (size_t)i);
171*340f5e56SDavid van Moolenbroek spacebuf[i] = '\0';
172*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "%s", spacebuf);
173*340f5e56SDavid van Moolenbroek l += i;
174*340f5e56SDavid van Moolenbroek
175*340f5e56SDavid van Moolenbroek if (nostat)
176*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "? ?");
177*340f5e56SDavid van Moolenbroek else {
178*340f5e56SDavid van Moolenbroek tm = gmtime(&sb.st_mtime);
179*340f5e56SDavid van Moolenbroek strftime(buf, sizeof buf, "%d-%b-%Y %R", tm);
180*340f5e56SDavid van Moolenbroek l += bozo_printf(httpd, "%s", buf);
181*340f5e56SDavid van Moolenbroek
182*340f5e56SDavid van Moolenbroek /* LMODLEN spaces */
183*340f5e56SDavid van Moolenbroek /*LINTED*/
184*340f5e56SDavid van Moolenbroek assert(/*CONSTCOND*/sizeof(spacebuf) > LMODLEN);
185*340f5e56SDavid van Moolenbroek i = (l < (LMODLEN+NAMELEN+1)) ?
186*340f5e56SDavid van Moolenbroek ((LMODLEN+NAMELEN+1) - l) : 0;
187*340f5e56SDavid van Moolenbroek i++;
188*340f5e56SDavid van Moolenbroek memset(spacebuf, ' ', (size_t)i);
189*340f5e56SDavid van Moolenbroek spacebuf[i] = '\0';
190*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "%s", spacebuf);
191*340f5e56SDavid van Moolenbroek
192*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "%12llukB",
193*340f5e56SDavid van Moolenbroek (unsigned long long)sb.st_size >> 10);
194*340f5e56SDavid van Moolenbroek }
195*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "\r\n");
196*340f5e56SDavid van Moolenbroek }
197*340f5e56SDavid van Moolenbroek
198*340f5e56SDavid van Moolenbroek closedir(dp);
199*340f5e56SDavid van Moolenbroek while (k--)
200*340f5e56SDavid van Moolenbroek free(deo[k]);
201*340f5e56SDavid van Moolenbroek free(deo);
202*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "</pre>");
203*340f5e56SDavid van Moolenbroek directory_hr(httpd);
204*340f5e56SDavid van Moolenbroek bozo_printf(httpd, "</body></html>\r\n\r\n");
205*340f5e56SDavid van Moolenbroek bozo_flush(httpd, stdout);
206*340f5e56SDavid van Moolenbroek
207*340f5e56SDavid van Moolenbroek done:
208*340f5e56SDavid van Moolenbroek free(file);
209*340f5e56SDavid van Moolenbroek return 1;
210*340f5e56SDavid van Moolenbroek }
211*340f5e56SDavid van Moolenbroek #endif /* NO_DIRINDEX_SUPPORT */
212*340f5e56SDavid van Moolenbroek
213