1 /*
2  * path.c
3  *
4  * (C)1998-2011 by Marc Huber <Marc.Huber@web.de>
5  * All rights reserved.
6  *
7  * $Id: path.c,v 1.12 2015/03/14 06:11:27 marc Exp marc $
8  *
9  */
10 
11 #include "headers.h"
12 #include <grp.h>
13 
14 static const char rcsid[] __attribute__ ((used)) = "$Id: path.c,v 1.12 2015/03/14 06:11:27 marc Exp marc $";
15 
parsepath(struct context * ctx,char * path)16 char *parsepath(struct context *ctx, char *path)
17 {
18     static char tmp[PATH_MAX + 1];
19     char *t = tmp;
20 
21     Debug((DEBUG_PATH, "+ %s(\"%s\")\n", __func__, path));
22 
23     while (*path) {
24 	if (*path == '/') {
25 	    if (*++path == '/')
26 		continue;
27 
28 	    if (*path == '.') {
29 		path++;
30 		if (*path == '/' || *path == 0)
31 		    continue;
32 
33 		if (*path == '.' && (*(path + 1) == '/' || *(path + 1) == 0)) {
34 		    if (t == tmp) {
35 			Debug((DEBUG_PATH, "- %s = NULL\n", __func__));
36 			return NULL;
37 		    }
38 		    path++;
39 		    if (*t == '/' && t > tmp)
40 			t--;
41 		    while (t > tmp && *t != '/')
42 			t--;
43 		    if ((u_int) (t - tmp) < ctx->rootlen) {
44 			if (t == tmp && ctx->rootlen == 0) {
45 			    tmp[1] = '/', tmp[0] = 0;
46 			    Debug((DEBUG_PATH, "- %s = \"/\"\n", __func__));
47 			    return tmp;
48 			}
49 			Debug((DEBUG_PATH, "- %s = NULL\n", __func__));
50 			return NULL;
51 		    }
52 		    continue;
53 		}
54 		path--;
55 	    }
56 	    path--;
57 	}
58 	*t++ = *path++;
59     }
60 
61     do
62 	*t-- = 0;
63     while (t >= tmp && *t == '/');
64 
65     if (!tmp[0])
66 	tmp[0] = '/', tmp[1] = 0;
67 
68     Debug((DEBUG_PATH, "- %s = %s\n", __func__, tmp));
69     return tmp;
70 }
71 
buildpath(struct context * ctx,char * path)72 char *buildpath(struct context *ctx, char *path)
73 {
74     static char tmp[PATH_MAX + 1];
75     char *t = tmp, *c = tmp;
76 #if defined(WITH_PCRE) || defined(WITH_PCRE2)
77     static char pcretmp[PATH_MAX + 1];
78 #endif				/* WITH_PCRE */
79 
80     Debug((DEBUG_PATH, "+ %s(\"%s\")\n", __func__, path));
81     Debug((DEBUG_PATH, "  cwd =\"%s\"\n", ctx->cwd));
82 
83     if (!path || (ctx->cwdlen + strlen(path) + 3 > PATH_MAX)) {
84 	Debug((DEBUG_PATH, "- %s = NULL\n", __func__));
85 	return NULL;
86     }
87 
88     if ((size_t) snprintf(tmp, sizeof(tmp), "%s/%s", path[0] == '/' ? ctx->root : ctx->cwd, path) >= sizeof(tmp)) {
89 	Debug((DEBUG_PATH, "- %s: path too long\n", __func__));
90 	return NULL;
91     }
92 
93     while (*c)
94 	if (*c == '/' && *(c + 1) == '/')
95 	    c++;
96 	else
97 	    *t++ = *c++;
98 
99     if (t > tmp + 1 && *(t - 1) == '/')
100 	t--;
101     *t = 0;
102 
103     t = parsepath(ctx, tmp);
104 
105     if ((!t || strncmp(t, ctx->root, ctx->rootlen)) ||
106 	(ctx->rootlen && t[ctx->rootlen] && (t[ctx->rootlen] != '/')) || (!ctx->allow_dotfiles && strstr(t, "/."))) {
107 	Debug((DEBUG_PATH, "- %s = NULL\n", __func__));
108 	return NULL;
109     }
110 #if defined(WITH_PCRE) || defined(WITH_PCRE2)
111     if (t && PCRE_exec(t, pcretmp, sizeof(pcretmp)))
112 	t = *pcretmp ? pcretmp : NULL;
113 #endif				/* WITH_PCRE */
114     Debug((DEBUG_PATH, "- %s = %s\n", __func__, t ? t : "NULL"));
115     return t;
116 }
117 
118 /* check_incoming: returns TRUE if valid upload path */
119 
check_incoming(struct context * ctx,char * path,u_int mask)120 int check_incoming(struct context *ctx, char *path, u_int mask)
121 {
122     char *t;
123     struct stat st;
124     Debug((DEBUG_PATH, "  check_incoming %s\n", path));
125     Debug((DEBUG_PATH, "  test1 %d\n", ctx->incoming ? 1 : 0));
126     Debug((DEBUG_PATH, "  test2 %s\n", strrchr(path, '/')));
127 
128     if (!ctx->incoming || !(t = strrchr(path, '/')) || regexec(ctx->incoming, path, 0, NULL, 0))
129 	return 0;
130     *t = 0;
131     Debug((DEBUG_PATH, "  regex passed"));
132     if (stat(path, &st)) {
133 	*t = '/';
134 	return 0;
135     }
136     *t = '/';
137     seteuid(0);
138     setgroups(0, NULL);
139     setegid(st.st_gid);
140     seteuid(st.st_uid);
141     current_uid = st.st_uid;
142     current_gid = st.st_gid;
143     update_ids = -1;
144     ctx->umask = mask ? mask : (u_int) (~(st.st_mode & 0777) | 022);
145     Debug((DEBUG_PATH, "  umask set to %.4o\n", ctx->umask));
146     return -1;
147 }
148