1 /*
2 * h_stor.c
3 * (C)1998-2011 by Marc Huber <Marc.Huber@web.de>
4 * All rights reserved.
5 *
6 * $Id: h_stor.c,v 1.16 2019/06/07 17:15:54 marc Exp marc $
7 *
8 */
9
10 #include "headers.h"
11 #include "misc/base64.h"
12
13 static const char rcsid[] __attribute__ ((used)) = "$Id: h_stor.c,v 1.16 2019/06/07 17:15:54 marc Exp marc $";
14
skipbytes(struct context * ctx,int cur)15 static void skipbytes(struct context *ctx, int cur __attribute__ ((unused)))
16 {
17 off_t ro = ctx->io_offset, off = 0;
18
19 DebugIn(DEBUG_BUFFER);
20
21 sigbus_cur = ctx->cfn;
22
23 if (chunk_get(ctx, NULL)) {
24 io_sched_pop(ctx->io, ctx);
25 ctx->dbufi = buffer_free_all(ctx->dbufi);
26 ctx->remaining = 0, ctx->offset = 0;
27 cleanup_file(ctx, ctx->ffn);
28 cleanup_data(ctx, ctx->ffn);
29 reply(ctx, MSG_451_Internal_error);
30 } else {
31 if (chunk_remaining(ctx)) {
32 char *u = ctx->chunk_start;
33 char lastchar = ctx->lastchar;
34 size_t len = MIN(ctx->chunk_length, (size_t) bufsize);
35 char *ul = u + len;
36
37 for (off = 0; ro && u < ul; ro--, off++, lastchar = *u++)
38 if (*u == '\n' && lastchar != '\r')
39 ro--;
40
41 ctx->lastchar = lastchar;
42 chunk_release(ctx, len);
43 }
44
45 if (!chunk_remaining(ctx))
46 ro = 0;
47
48 if (!ro) {
49 ctx->dbufi = buffer_free_all(ctx->dbufi);
50 lseek(ctx->ffn, ctx->offset + off, SEEK_SET);
51 ctx->remaining = 0, ctx->offset = 0;
52
53 if (io_get_cb_i(ctx->io, ctx->dfn) == (void *) socket2buffer) {
54 /* already connected */
55 io_clr_o(ctx->io, ctx->dfn);
56 io_set_i(ctx->io, ctx->dfn);
57 }
58 io_sched_pop(ctx->io, ctx);
59 } else
60 io_sched_renew_proc(ctx->io, ctx, (void *) skipbytes);
61
62 ctx->io_offset = ro;
63 }
64
65 DebugOut(DEBUG_BUFFER);
66 }
67
strrandom(char * s,int len)68 static void strrandom(char *s, int len)
69 {
70 size_t i, bl = 4 * ((len + 2) / 3), tl = len + 8;
71 char *t = alloca(tl);
72 size_t j = sizeof(u_int) * bl;
73 size_t *b = alloca(j);
74
75 for (i = 0; i < bl; i++)
76 b[i] = rand();
77
78 base64enc((char *) b, bl, t, &tl);
79
80 strncpy(s, t, len);
81 s[len - 1] = 0;
82 }
83
myopen(char * pathname,int flags,mode_t mode,int stou)84 static int myopen(char *pathname, int flags, mode_t mode, int stou)
85 {
86 if (stou) {
87 int fn, tries = 0;
88 char *p = pathname;
89 for (; *p; p++);
90 if (p - pathname > 5) {
91 p -= 6;
92 do {
93 strrandom(p, 6);
94 fn = open(pathname, flags, mode);
95 if (fn > -1)
96 return fn;
97 }
98 while (++tries < 100 && fn < 0 && errno == EEXIST);
99 }
100 return -1;
101 }
102 return open(pathname, flags, mode);
103 }
104
h_xstor(struct context * ctx,char * arg,int flags)105 static void h_xstor(struct context *ctx, char *arg, int flags)
106 {
107 char *t;
108 int f = -1;
109 struct stat st;
110 int stou = 0;
111 char tbuf[PATH_MAX + 13];
112
113 DebugIn(DEBUG_COMMAND);
114
115 if (ctx->transfer_in_progress) {
116 reply(ctx, MSG_501_Transfer_in_progress);
117 DebugOut(DEBUG_COMMAND);
118 return;
119 }
120
121 ctx->outgoing_data = 0;
122 if (ctx->dfn > -1 && io_get_cb_i(ctx->io, ctx->dfn) == (void *) accept_data) {
123 io_set_i(ctx->io, ctx->dfn);
124 io_clr_o(ctx->io, ctx->dfn);
125 io_set_cb_e(ctx->io, ctx->dfn, (void *) cleanup_data);
126 io_set_cb_h(ctx->io, ctx->dfn, (void *) cleanup_data);
127 }
128
129 quota_add(ctx, 0);
130
131 if (ctx->quota_path && (ctx->quota_ondisk >= ctx->quota_limit)) {
132 reply(ctx, MSG_451_quota_exceeded);
133 logmsg("%s: quota limit reached", ctx->user);
134 DebugOut(DEBUG_COMMAND);
135 return;
136 }
137
138 if (!arg) {
139 stou = -1;
140 snprintf(tbuf, sizeof(tbuf), "%s/stou.XXXXXX", ctx->cwd);
141 arg = tbuf;
142
143 t = buildpath(ctx, arg);
144 } else if (acl_binary_only(ctx, arg, (t = buildpath(ctx, arg)))) {
145 reply(ctx, MSG_504_no_ascii);
146 cleanup_data_reuse(ctx, ctx->dfn);
147 DebugOut(DEBUG_COMMAND);
148 return;
149 }
150
151 st.st_size = 0;
152
153 if (t)
154 acl_set_umask(ctx, arg, t);
155
156 if (ctx->anonymous || stou)
157 flags |= O_EXCL;
158
159 if (t && (!ctx->anonymous || check_incoming(ctx, t, 077)) &&
160 !pickystat_path(ctx, &st, t) &&
161 (stat(t, &st), (f = myopen(t, O_RDWR | O_CREAT | O_LARGEFILE | O_NOFOLLOW | flags, ctx->chmod_filemask | (0644 & ~ctx->umask), stou)) > -1)) {
162
163 fcntl(f, F_SETFD, FD_CLOEXEC);
164
165 ctx->quota_filesize_before_stor = st.st_size;
166 ctx->quota_update_on_close = 1;
167
168 if (ctx->dfn < 0)
169 connect_port(ctx);
170
171 if (ctx->dfn < 0) {
172 reply(ctx, MSG_431_Opening_datacon_failed);
173 close(f);
174 ctx->dbuf = buffer_free_all(ctx->dbuf);
175 DebugOut(DEBUG_COMMAND);
176 return;
177 }
178
179 ctx->ffn = f;
180 if (strlen(t) >= sizeof(ctx->filename)) {
181 logerr("buffer too small in %s:%d (%s/%s)", __FILE__, __LINE__, ctx->user, t);
182 reply(ctx, MSG_551_Internal_error);
183 close(f);
184 cleanup(ctx, ctx->dfn);
185 ctx->dbuf = buffer_free_all(ctx->dbuf);
186 DebugOut(DEBUG_COMMAND);
187 return;
188 }
189 strcpy(ctx->filename, t);
190 ctx->filesize = 0;
191 ctx->bytecount = 0;
192
193 if (io_get_cb_i(ctx->io, ctx->dfn) == (void *) socket2buffer || is_connected(ctx->dfn)) {
194 if (stou)
195 replyf(ctx, "125 FILE: %s\r\n", ctx->filename + ctx->rootlen);
196 else
197 replyf(ctx, MSG_125_Starting_dc, ctx->use_ascii ? "ASCII" : "BINARY", ctx->use_tls_d ? "TLS " : "");
198 } else {
199 if (stou)
200 replyf(ctx, "150 FILE: %s\r\n", ctx->filename + ctx->rootlen);
201 else
202 replyf(ctx, MSG_150_Opening_dc, ctx->use_ascii ? "ASCII" : "BINARY", ctx->use_tls_d ? "TLS " : "");
203 }
204
205 ctx->transfer_in_progress = 1;
206
207 if (ctx->io_offset) {
208 if (ctx->use_ascii) {
209 ctx->offset = 0;
210 ctx->remaining = st.st_size;
211 io_sched_add(ctx->io, ctx, (void *) skipbytes, 0, 0);
212 #ifdef WITH_MMAP
213 if (use_mmap)
214 ctx->iomode = IOMODE_mmap;
215 else
216 #endif
217 ctx->iomode = IOMODE_read, ctx->iomode_fixed = 1;
218 } else {
219 lseek(f, ctx->io_offset, SEEK_SET);
220 ctx->io_offset = 0;
221 }
222 }
223
224 if (io_get_cb_i(ctx->io, ctx->dfn) == (void *) socket2buffer) {
225 /* already connected */
226 io_clr_o(ctx->io, ctx->dfn);
227 io_set_i(ctx->io, ctx->dfn);
228 }
229
230 ctx->transferstart = io_now.tv_sec;
231 ctx->count_files++;
232 } else {
233 if (stou && errno == EEXIST)
234 reply(ctx, MSG_451_unique_file_failure);
235 else
236 reply(ctx, MSG_550_Permission_denied);
237 cleanup_data_reuse(ctx, ctx->dfn);
238 }
239
240 DebugOut(DEBUG_COMMAND);
241 }
242
h_stor(struct context * ctx,char * arg)243 void h_stor(struct context *ctx, char *arg)
244 {
245 DebugIn(DEBUG_COMMAND);
246 h_xstor(ctx, arg, (ctx->io_offset ? 0 : O_TRUNC));
247 DebugOut(DEBUG_COMMAND);
248 }
249
h_stou(struct context * ctx,char * arg)250 void h_stou(struct context *ctx, char *arg __attribute__ ((unused)))
251 {
252 DebugIn(DEBUG_COMMAND);
253 ctx->io_offset = 0;
254 h_xstor(ctx, NULL, O_TRUNC);
255 DebugOut(DEBUG_COMMAND);
256 }
257
h_appe(struct context * ctx,char * arg)258 void h_appe(struct context *ctx, char *arg)
259 {
260 DebugIn(DEBUG_COMMAND);
261 ctx->io_offset = 0;
262 h_xstor(ctx, arg, O_APPEND);
263 DebugOut(DEBUG_COMMAND);
264 }
265