From 41241ca044a55ce1c5006cc4581f643fd3e5b20d Mon Sep 17 00:00:00 2001 From: reyk Date: Wed, 13 Aug 2014 16:04:28 +0000 Subject: [PATCH] Provide a failsafe version of the path_info() function that doesn't need a temporary path variable. Based on an initial diff from chrisz@. "Commit any failsafe version and I'm ok with it" chrisz@ --- usr.sbin/httpd/httpd.c | 31 ++++++++++++++++++------------- usr.sbin/httpd/httpd.h | 4 ++-- usr.sbin/httpd/server_fcgi.c | 11 +++++------ 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/usr.sbin/httpd/httpd.c b/usr.sbin/httpd/httpd.c index d5ca6e4067c..4b631ec7353 100644 --- a/usr.sbin/httpd/httpd.c +++ b/usr.sbin/httpd/httpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: httpd.c,v 1.18 2014/08/13 08:08:55 chrisz Exp $ */ +/* $OpenBSD: httpd.c,v 1.19 2014/08/13 16:04:28 reyk Exp $ */ /* * Copyright (c) 2014 Reyk Floeter @@ -580,28 +580,33 @@ canonicalize_path(const char *input, char *path, size_t len) return (path); } -ssize_t -path_info(char *name) +size_t +path_info(char *path) { - char *p, *start, *end; - char path[MAXPATHLEN]; + char *p, *start, *end, ch; struct stat st; - - if (strlcpy(path, name, sizeof(path)) >= sizeof(path)) - return (-1); + int ret; start = path; end = start + strlen(path); - for (p = end; p >= start; p--) { - if (*p != '/') + for (p = end; p > start; p--) { + /* Scan every path component from the end and at each '/' */ + if (p < end && *p != '/') continue; - if (stat(path, &st) == 0) - break; + + /* Temporarily cut the path component out */ + ch = *p; *p = '\0'; + ret = stat(path, &st); + *p = ch; + + /* Break if the initial path component was found */ + if (ret == 0) + break; } - return (strlen(path)); + return (p - start); } void diff --git a/usr.sbin/httpd/httpd.h b/usr.sbin/httpd/httpd.h index 1a8042840c0..371dd1caac0 100644 --- a/usr.sbin/httpd/httpd.h +++ b/usr.sbin/httpd/httpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: httpd.h,v 1.52 2014/08/08 18:29:42 reyk Exp $ */ +/* $OpenBSD: httpd.h,v 1.53 2014/08/13 16:04:28 reyk Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter @@ -537,7 +537,7 @@ void event_again(struct event *, int, short, struct timeval *, struct timeval *, void *); const char *canonicalize_host(const char *, char *, size_t); const char *canonicalize_path(const char *, char *, size_t); -ssize_t path_info(char *); +size_t path_info(char *); void imsg_event_add(struct imsgev *); int imsg_compose_event(struct imsgev *, u_int16_t, u_int32_t, pid_t, int, void *, u_int16_t); diff --git a/usr.sbin/httpd/server_fcgi.c b/usr.sbin/httpd/server_fcgi.c index e740883c144..d191ef21aee 100644 --- a/usr.sbin/httpd/server_fcgi.c +++ b/usr.sbin/httpd/server_fcgi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server_fcgi.c,v 1.31 2014/08/11 15:26:33 deraadt Exp $ */ +/* $OpenBSD: server_fcgi.c,v 1.32 2014/08/13 16:04:28 reyk Exp $ */ /* * Copyright (c) 2014 Florian Obser @@ -100,7 +100,7 @@ server_fcgi(struct httpd *env, struct client *clt) struct fcgi_record_header *h; struct fcgi_begin_request_body *begin; char hbuf[MAXHOSTNAMELEN]; - ssize_t scriptlen; + ssize_t scriptlen, pathlen; int fd = -1, ret; const char *errstr = NULL; char *str, *p, *script = NULL; @@ -191,15 +191,14 @@ server_fcgi(struct httpd *env, struct client *clt) h->type = FCGI_PARAMS; h->content_len = param.total_len = 0; - if (asprintf(&script, "%s%s", srv_conf->root, + if ((pathlen = (ssize_t)asprintf(&script, "%s%s", srv_conf->root, desc->http_path_alias != NULL ? - desc->http_path_alias : desc->http_path) == -1 || - (scriptlen = path_info(script)) == -1) { + desc->http_path_alias : desc->http_path)) == -1) { errstr = "failed to get script name"; goto fail; } - if (scriptlen) { + if ((scriptlen = path_info(script)) < pathlen) { if (fcgi_add_param(¶m, "PATH_INFO", script + scriptlen, clt) == -1) { errstr = "failed to encode param"; -- 2.20.1