Example #1
0
/*
 * output a directory index.  return 1 if it actually did something..
 */
int
bozo_dir_index(bozo_httpreq_t *request, const char *dirpath, int isindex)
{
	bozohttpd_t *httpd = request->hr_httpd;
	struct stat sb;
	struct dirent **de, **deo;
	struct tm *tm;
	DIR *dp;
	char buf[MAXPATHLEN];
	char spacebuf[48];
	char *file = NULL, *printname = NULL;
	int l, k, j, i;

	if (!isindex || !httpd->dir_indexing)
		return 0;

	if (strlen(dirpath) <= strlen(httpd->index_html))
		dirpath = ".";
	else {
		file = bozostrdup(httpd, request, dirpath);

		file[strlen(file) - strlen(httpd->index_html)] = '\0';
		dirpath = file;
	}
	debug((httpd, DEBUG_FAT, "bozo_dir_index: dirpath ``%s''", dirpath));
	if (stat(dirpath, &sb) < 0 ||
	    (dp = opendir(dirpath)) == NULL) {
		if (errno == EPERM)
			(void)bozo_http_error(httpd, 403, request,
			    "no permission to open directory");
		else if (errno == ENOENT)
			(void)bozo_http_error(httpd, 404, request, "no file");
		else
			(void)bozo_http_error(httpd, 500, request,
					"open directory");
		goto done;
		/* NOTREACHED */
	}

	bozo_printf(httpd, "%s 200 OK\r\n", request->hr_proto);

	if (request->hr_proto != httpd->consts.http_09) {
		bozo_print_header(request, NULL, "text/html", "");
		bozo_printf(httpd, "\r\n");
	}
	bozo_flush(httpd, stdout);

	if (request->hr_method == HTTP_HEAD) {
		closedir(dp);
		goto done;
	}

#ifndef NO_USER_SUPPORT
	if (request->hr_user) {
		bozoasprintf(httpd, &printname, "~%s/%s",
			     request->hr_user, request->hr_file);
	} else
		printname = bozostrdup(httpd, request, request->hr_file);
#else
	printname = bozostrdup(httpd, request, request->hr_file);
#endif /* !NO_USER_SUPPORT */

	bozo_printf(httpd,
		"<html><head><title>Index of %s</title></head>\r\n",
		printname);
	bozo_printf(httpd, "<body><h1>Index of %s</h1>\r\n",
		printname);
	bozo_printf(httpd, "<pre>\r\n");
#define NAMELEN 40
#define LMODLEN 19
	bozo_printf(httpd, "Name                                     "
	    "Last modified          "
	    "Size\n");
	bozo_printf(httpd, "</pre>");
	directory_hr(httpd);
	bozo_printf(httpd, "<pre>");

	for (j = k = scandir(dirpath, &de, NULL, alphasort), deo = de;
	    j--; de++) {
		int nostat = 0;
		char *name = (*de)->d_name;
		char *urlname, *htmlname;

		if (strcmp(name, ".") == 0 ||
		    (strcmp(name, "..") != 0 &&
		     httpd->hide_dots && name[0] == '.'))
			continue;

		snprintf(buf, sizeof buf, "%s/%s", dirpath, name);
		if (stat(buf, &sb))
			nostat = 1;

		l = 0;

		urlname = bozo_escape_rfc3986(httpd, name, 0);
		htmlname = bozo_escape_html(httpd, name);
		if (htmlname == NULL)
			htmlname = name;
		if (strcmp(name, "..") == 0) {
			bozo_printf(httpd, "<a href=\"../\">");
			l += bozo_printf(httpd, "Parent Directory");
		} else if (S_ISDIR(sb.st_mode)) {
			bozo_printf(httpd, "<a href=\"%s/\">", urlname);
			l += bozo_printf(httpd, "%s/", htmlname);
		} else if (strchr(name, ':') != NULL) {
			/* RFC 3986 4.2 */
			bozo_printf(httpd, "<a href=\"./%s\">", urlname);
			l += bozo_printf(httpd, "%s", htmlname);
		} else {
			bozo_printf(httpd, "<a href=\"%s\">", urlname);
			l += bozo_printf(httpd, "%s", htmlname);
		}
		if (htmlname != name)
			free(htmlname);
		bozo_printf(httpd, "</a>");

		/* NAMELEN spaces */
		/*LINTED*/
		assert(/*CONSTCOND*/sizeof(spacebuf) > NAMELEN);
		i = (l < NAMELEN) ? (NAMELEN - l) : 0;
		i++;
		memset(spacebuf, ' ', (size_t)i);
		spacebuf[i] = '\0';
		bozo_printf(httpd, "%s", spacebuf);
		l += i;

		if (nostat)
			bozo_printf(httpd, "?                         ?");
		else {
			tm = gmtime(&sb.st_mtime);
			strftime(buf, sizeof buf, "%d-%b-%Y %R", tm);
			l += bozo_printf(httpd, "%s", buf);

			/* LMODLEN spaces */
			/*LINTED*/
			assert(/*CONSTCOND*/sizeof(spacebuf) > LMODLEN);
			i = (l < (LMODLEN+NAMELEN+1)) ?
				((LMODLEN+NAMELEN+1) - l) : 0;
			i++;
			memset(spacebuf, ' ', (size_t)i);
			spacebuf[i] = '\0';
			bozo_printf(httpd, "%s", spacebuf);

			bozo_printf(httpd, "%12llukB",
				    (unsigned long long)sb.st_size >> 10);
		}
		bozo_printf(httpd, "\r\n");
	}

	closedir(dp);
	while (k--)
        	free(deo[k]);
	free(deo);
	bozo_printf(httpd, "</pre>");
	directory_hr(httpd);
	bozo_printf(httpd, "</body></html>\r\n\r\n");
	bozo_flush(httpd, stdout);

done:
	free(file);
	free(printname);
	return 1;
}
/*
 * bozo_user_transform does this:
 *	- chdir's /~user/public_html
 *	- returns the rest of the file, index.html appended if required
 *	- returned malloced file to serve in request->hr_file,
 *        ala transform_request().
 *
 * transform_request() is supposed to check that we have user support
 * enabled.
 */
int
bozo_user_transform(bozo_httpreq_t *request, int *isindex)
{
	bozohttpd_t *httpd = request->hr_httpd;
	char	c, *s, *file = NULL;
	struct	passwd *pw;

	*isindex = 0;

	if ((s = strchr(request->hr_file + 2, '/')) != NULL) {
		*s++ = '\0';
		c = s[strlen(s)-1];
		*isindex = (c == '/' || c == '\0');
	}

	debug((httpd, DEBUG_OBESE, "looking for user %s",
		request->hr_file + 2));
	pw = getpwnam(request->hr_file + 2);
	/* fix this up immediately */
	if (s)
		s[-1] = '/';
	if (pw == NULL) {
		(void)bozo_http_error(httpd, 404, request, "no such user");
		return 0;
	}

	debug((httpd, DEBUG_OBESE, "user %s dir %s/%s uid %d gid %d",
	      pw->pw_name, pw->pw_dir, httpd->public_html,
	      pw->pw_uid, pw->pw_gid));

	if (chdir(pw->pw_dir) < 0) {
		bozo_warn(httpd, "chdir1 error: %s: %s", pw->pw_dir,
			strerror(errno));
		(void)bozo_http_error(httpd, 404, request,
			"can't chdir to homedir");
		return 0;
	}
	if (chdir(httpd->public_html) < 0) {
		bozo_warn(httpd, "chdir2 error: %s: %s", httpd->public_html,
			strerror(errno));
		(void)bozo_http_error(httpd, 404, request,
			"can't chdir to public_html");
		return 0;
	}
	if (s == NULL || *s == '\0') {
		file = bozostrdup(httpd, httpd->index_html);
	} else {
		file = bozomalloc(httpd, strlen(s) +
		    (*isindex ? strlen(httpd->index_html) + 1 : 1));
		strcpy(file, s);
		if (*isindex)
			strcat(file, httpd->index_html);
	}

	/* see transform_request() */
	if (*file == '/' || strcmp(file, "..") == 0 ||
	    strstr(file, "/..") || strstr(file, "../")) {
		(void)bozo_http_error(httpd, 403, request, "illegal request");
		free(file);
		return 0;
	}

	if (bozo_auth_check(request, file)) {
		free(file);
		return 0;
	}

	free(request->hr_file);
	request->hr_file = file;

	debug((httpd, DEBUG_FAT, "transform_user returning %s under %s", file,
	    pw->pw_dir));
	return 1;
}