1 /*
2  * cleanup.c
3  * (C)1997-2011 by Marc Huber <Marc.Huber@web.de>
4  * All rights reserved.
5  *
6  * $Id: cleanup.c,v 1.18 2015/03/14 06:11:24 marc Exp marc $
7  *
8  */
9 
10 #include "headers.h"
11 
12 static const char rcsid[] __attribute__ ((used)) = "$Id: cleanup.c,v 1.18 2015/03/14 06:11:24 marc Exp marc $";
13 
14 static void cleanup_context(struct context *, int);
15 
cleanup_control_finish(struct context * ctx,int cur)16 static void cleanup_control_finish(struct context *ctx, int cur)
17 {
18     Debug((DEBUG_PROC, "cleanup_control_finish\n"));
19     io_close(ctx->io, cur);
20     ctx->cfn = -1;
21 
22     if (ctx->sctp_fn > -1) {
23 	close(ctx->sctp_fn);
24 	ctx->sctp_fn = -1;
25     }
26 
27     cleanup_context(ctx, -1);
28 }
29 
cleanup_control_ssl_error(struct context * ctx,int cur)30 void cleanup_control_ssl_error(struct context *ctx, int cur)
31 {
32 #ifdef WITH_SSL
33     if (ctx->ssl_c) {
34 	SSL_free(ctx->ssl_c);
35 	ctx->ssl_c = NULL;
36     }
37 #endif
38     cleanup_control(ctx, cur);
39 }
40 
cleanup_data_ssl_error(struct context * ctx,int cur)41 void cleanup_data_ssl_error(struct context *ctx, int cur)
42 {
43 #ifdef WITH_SSL
44     if (ctx->ssl_d) {
45 	SSL_free(ctx->ssl_d);
46 	ctx->ssl_d = NULL;
47     }
48 #endif
49     cleanup_data(ctx, cur);
50 }
51 
cleanup_data_finish(struct context * ctx,int cur)52 static void cleanup_data_finish(struct context *ctx, int cur __attribute__ ((unused)))
53 {
54     DebugIn(DEBUG_PROC | DEBUG_NET);
55     if (ctx->dfn > -1) {
56 	io_close(ctx->io, ctx->dfn);
57 	ctx->dfn = -1;
58 	ctx->buffer_filled = 0;
59 	ctx->ascii_in_buffer = 0;
60 	ctx->conversion = CONV_NONE;
61 	cleanup_context(ctx, -1);
62     }
63     DebugOut(DEBUG_PROC | DEBUG_NET);
64 }
65 
66 #ifdef WITH_SSL
ssl_cleanup_control(struct context * ctx,int cur)67 static void ssl_cleanup_control(struct context *ctx, int cur __attribute__ ((unused)))
68 {
69     Debug((DEBUG_PROC, "ssl_cleanup_control\n"));
70 
71     if (io_SSL_shutdown(ctx->ssl_c, ctx->io, ctx->cfn, (void *) ssl_cleanup_control) < 0 && errno == EAGAIN)
72 	return;
73 
74     SSL_free(ctx->ssl_c);
75     ctx->ssl_c = NULL;
76     cleanup_control_finish(ctx, ctx->cfn);
77 }
78 
ssl_cleanup_data(struct context * ctx,int cur)79 static void ssl_cleanup_data(struct context *ctx, int cur __attribute__ ((unused)))
80 {
81     Debug((DEBUG_PROC, "ssl_cleanup_data\n"));
82 
83     if (io_SSL_shutdown(ctx->ssl_d, ctx->io, ctx->dfn, (void *) ssl_cleanup_data) < 0 && errno == EAGAIN)
84 	return;
85 
86     SSL_free(ctx->ssl_d);
87     ctx->ssl_d = NULL;
88     cleanup_data_finish(ctx, ctx->dfn);
89 }
90 #endif				/* WITH_SSL */
91 
cleanup_ident(struct context * ctx,int cur)92 void cleanup_ident(struct context *ctx, int cur __attribute__ ((unused)))
93 {
94     DebugIn(DEBUG_PROC);
95 
96     if (ctx->ifn > -1) {
97 	io_clr_i(ctx->io, ctx->ifn);
98 	io_clr_o(ctx->io, ctx->ifn);
99 
100 	io_close(ctx->io, ctx->ifn);
101 	Xfree(&ctx->ident_buf);
102 	ctx->ifn = -1;
103     }
104 
105     DebugOut(DEBUG_PROC);
106 }
107 
cleanup_control(struct context * ctx,int cur)108 void cleanup_control(struct context *ctx, int cur __attribute__ ((unused)))
109 {
110     DebugIn(DEBUG_PROC);
111 
112     if (ctx->cfn > -1) {
113 #ifdef WITH_SSL
114 	if (io_get_cb_i(ctx->io, ctx->cfn) == (void *) ssl_cleanup_control) {
115 	    Debug((DEBUG_PROC, "- %s #C\n", __func__));
116 	    return;
117 	}
118 #endif
119 
120 	ftp_log(ctx, LOG_EVENT, ctx->login_logged ? "logout" : "reject");
121 
122 	if (ctx->ffn < 0 && ctx->dbuf)
123 	    cleanup_data(ctx, ctx->dfn);
124 
125 #ifdef WITH_SSL
126 	if (ctx->ssl_c) {
127 	    io_clr_i(ctx->io, ctx->cfn);
128 	    io_clr_o(ctx->io, ctx->cfn);
129 	    ssl_cleanup_control(ctx, ctx->cfn);
130 	} else
131 #endif				/* WITH_SSL */
132 	    cleanup_control_finish(ctx, ctx->cfn);
133     }
134     DebugOut(DEBUG_PROC);
135 }
136 
cleanup_data_reuse(struct context * ctx,int cur)137 void cleanup_data_reuse(struct context *ctx, int cur __attribute__ ((unused)))
138 {
139     if (ctx->dfn > -1) {
140 	ctx->outgoing_data = 0;
141 	io_clr_o(ctx->io, ctx->dfn);
142 	io_clr_i(ctx->io, ctx->dfn);
143 
144 	if (io_get_cb_o(ctx->io, ctx->dfn) == (void *) buffer2socket)
145 	    io_set_cb_i(ctx->io, ctx->dfn, (void *) socket2buffer);
146 	else if (io_get_cb_i(ctx->io, ctx->dfn) == (void *) socket2buffer)
147 	    io_set_cb_o(ctx->io, ctx->dfn, (void *) buffer2socket);
148     }
149     ctx->estp = 0;
150     ctx->estp_valid = 0;
151     ctx->passive_transfer = 0;
152     ctx->transfer_in_progress = 0;
153 }
154 
cleanup_data(struct context * ctx,int cur)155 void cleanup_data(struct context *ctx, int cur __attribute__ ((unused)))
156 {
157     int ffn = ctx->ffn;
158     int outgoing_data = ctx->outgoing_data;
159 
160     DebugIn(DEBUG_PROC | DEBUG_NET);
161 
162     ctx->estp = 0;
163     ctx->estp_valid = 0;
164     ctx->passive_transfer = 0;
165     ctx->transfer_in_progress = 0;
166 
167     if (ctx->dfn > -1) {
168 	ctx->iomode = IOMODE_dunno, ctx->iomode_fixed = 0;
169 #ifdef WITH_SSL
170 	if (io_get_cb_i(ctx->io, ctx->dfn) == (void *) ssl_cleanup_data) {
171 	    Debug((DEBUG_PROC, "- %s #C\n", __func__));
172 	    return;
173 	}
174 #endif
175 
176 	if (io_sched_del(ctx->io, ctx, (void *) cleanup_data)) {
177 	    if (io_get_cb_i(ctx->io, ctx->dfn) == (void *) connect_data)
178 		reply(ctx, MSG_431_Opening_datacon_failed);
179 	    ctx->dbufi = buffer_free_all(ctx->dbufi);
180 	    if (ctx->ffn < 0 || io_get_cb_i(ctx->io, ctx->dfn) != (void *) socket2buffer) {
181 		ctx->dbuf = buffer_free_all(ctx->dbuf);
182 		if (ctx->ffn > -1)
183 		    cleanup_file(ctx, ctx->ffn);
184 	    }
185 	}
186 
187 	Debug((DEBUG_PROC | DEBUG_NET, "  ctx->dfn: %d\n", ctx->dfn));
188 
189 	io_clr_cb_i(ctx->io, ctx->dfn);
190 	io_clr_cb_o(ctx->io, ctx->dfn);
191 
192 	if (ctx->ffn < 0 || outgoing_data) {
193 	    ctx->dbuf = buffer_free_all(ctx->dbuf);
194 	    ctx->dbufi = buffer_free_all(ctx->dbufi);
195 	}
196 
197 	/* reset remote data CEP to defaults */
198 	ctx->sa_d_remote = ctx->sa_c_remote;
199 
200 #ifdef WITH_SSL
201 	if (ctx->ssl_d) {
202 	    io_clr_i(ctx->io, ctx->dfn);
203 	    io_clr_o(ctx->io, ctx->dfn);
204 	    ssl_cleanup_data(ctx, ctx->dfn);
205 	} else
206 #endif				/* WITH_SSL */
207 	    cleanup_data_finish(ctx, ctx->dfn);
208     }
209     if (ffn > -1) {
210 	if (outgoing_data)
211 	    cleanup_file(ctx, ffn);
212 	else
213 	    buffer2file(ctx, ffn);
214     }
215 
216     DebugOut(DEBUG_PROC | DEBUG_NET);
217 }
218 
cleanup_file(struct context * ctx,int cur)219 int cleanup_file(struct context *ctx, int cur __attribute__ ((unused)))
220 {
221     int result = 0;
222 
223     DebugIn(DEBUG_PROC);
224 
225     if (ctx->ffn > -1) {
226 	Debug((DEBUG_PROC, "  ctx->ffn: %d\n", ctx->ffn));
227 
228 	ctx->io_offset = 0;
229 	ctx->io_offset_start = 0;
230 	ctx->io_offset_end = -1;
231 
232 	if (ctx->quota_path && ctx->quota_update_on_close) {
233 	    struct stat st;
234 	    fstat(ctx->ffn, &st);
235 	    quota_add(ctx, st.st_size - ctx->quota_filesize_before_stor);
236 	}
237 
238 	result = close(ctx->ffn);
239 
240 	ctx->ffn = -1;
241 	cleanup_context(ctx, -1);
242     }
243 
244     DebugOut(DEBUG_PROC);
245 
246     return result;
247 }
248 
cleanup_context(struct context * ctx,int cur)249 static void cleanup_context(struct context *ctx, int cur __attribute__ ((unused)))
250 {
251     DebugIn(DEBUG_PROC);
252 
253     if (ctx->ffn > -1 || ctx->dfn > -1 || ctx->cfn > -1) {
254 	Debug((DEBUG_PROC, "- %s (not yet)\n", __func__));
255 	return;
256     }
257 
258     if (ctx->is_client) {
259 	struct scm_data sd;
260 	sd.type = SCM_DONE;
261 	if (common_data.scm_send_msg(0, &sd, -1))
262 	    die_when_idle = -1;
263 
264 	common_data.users_cur--;
265 	if (common_data.users_cur == 0 && die_when_idle) {
266 	    Debug((DEBUG_PROC, "exiting -- process out of use\n"));
267 	    mavis_drop(mcx);
268 	    logmsg("Terminating, no longer needed.");
269 	    exit(EX_OK);
270 	}
271     }
272 
273     if (ctx->ifn > -1)
274 	cleanup_ident(ctx, ctx->ifn);
275 
276 #ifdef WITH_LWRES
277     if (ctx->reverse)
278 	Xfree(&ctx->reverse);
279     else
280 	io_dns_cancel(idc, ctx);
281 #endif				/* WITH_LWRES */
282 
283 #ifdef WITH_SSL
284     Xfree(&ctx->certsubj);
285     Xfree(&ctx->certsubjaltname);
286 #endif
287 
288     ctx->pst_valid = 0;
289 
290     Xfree(&ctx->ident_buf);
291     Xfree(&ctx->ident_user);
292     Xfree(&ctx->user);
293     Xfree(&ctx->email);
294     Xfree(&ctx->vhost);
295     Xfree(&ctx->visited_dirs);
296     if (ctx->auth_in_progress)
297 	mavis_cancel(mcx, ctx);
298 
299 #ifdef WITH_ZLIB
300     if (ctx->zstream) {
301 	deflateEnd(ctx->zstream);
302 	Xfree(&ctx->zstream);
303     }
304 #endif
305 
306     RB_tree_delete(ctx->filelist);
307 
308     while (io_sched_pop(ctx->io, ctx));
309 
310     if (ctx->dirfn > -1)
311 	close(ctx->dirfn);
312 
313     if (ctx->incoming) {
314 	regfree(ctx->incoming);
315 	free(ctx->incoming);
316     }
317 
318     Xfree(&ctx->quota_path);
319 
320     buffer_free_all(ctx->cbufi);
321     buffer_free_all(ctx->cbufo);
322     buffer_free_all(ctx->dbuf);
323     buffer_free_all(ctx->dbufi);
324     free(ctx);
325 
326     set_proctitle(die_when_idle ? ACCEPT_NEVER : ACCEPT_YES);
327 
328     DebugOut(DEBUG_PROC);
329 }
330 
cleanup(struct context * ctx,int cur)331 void cleanup(struct context *ctx, int cur __attribute__ ((unused)))
332 {
333     struct io_context *io = ctx->io;
334     int cfn = ctx->cfn;
335     int dfn = ctx->dfn;
336     int ffn = ctx->ffn;
337 
338     Debug((DEBUG_PROC, "+ %s(%d)\n", __func__, cur));
339 
340     while (io_sched_pop(ctx->io, ctx));
341 
342     if (dfn > -1 && io_get_ctx(io, dfn))
343 	cleanup_data(ctx, dfn);
344     if (ffn > -1 && io_get_ctx(io, ffn))
345 	cleanup_file(ctx, ffn);
346     if (cfn > -1 && io_get_ctx(io, cfn))
347 	cleanup_control(ctx, cfn);
348 
349     DebugOut(DEBUG_PROC);
350 }
351 
cleanup_spawnd(struct context * ctx,int cur)352 void cleanup_spawnd(struct context *ctx __attribute__ ((unused)), int cur __attribute__ ((unused)))
353 {
354     if (common_data.users_cur == 0) {
355 	Debug((DEBUG_PROC, "exiting -- process out of use\n"));
356 	mavis_drop(mcx);
357 	logmsg("Terminating, no longer needed.");
358 	exit(EX_OK);
359     }
360     die_when_idle = -1;
361     set_proctitle(ACCEPT_NEVER);
362 }
363