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