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