Пример #1
0
static void *Mavis_drop(mavis_ctx * mcx)
{
    void *handle = NULL;
    DebugIn(DEBUG_MAVIS);

#ifdef HAVE_mavis_drop_in
    mavis_drop_in(mcx);
#endif

    if (mcx->down)
	dlclose(mcx->down->drop(mcx->down));

#ifdef HAVE_mavis_drop_out
    mavis_drop_out(mcx);
#endif

    mavis_script_drop(&mcx->script_in);
    mavis_script_drop(&mcx->script_out);

    av_free(mcx->ac_bak);
    mcx->ac_bak = NULL;

    handle = mcx->handle;

    free(mcx);

    DebugOut(DEBUG_MAVIS);
    return handle;
}
Пример #2
0
static int Mavis_recv(mavis_ctx * mcx, av_ctx ** ac, void *app_ctx)
{
    int result = MAVIS_DOWN;
    DebugIn(DEBUG_MAVIS);

#ifdef HAVE_mavis_recv_in
    result = mavis_recv_in(mcx, ac, app_ctx);
#endif

    if (result == MAVIS_DOWN && mcx->down)
	result = mcx->down->recv(mcx->down, ac, app_ctx);

#ifdef HAVE_mavis_recv_out
    if (result == MAVIS_FINAL)
	result = mavis_recv_out(mcx, ac);
#endif

    if (result == MAVIS_DOWN)
	result = MAVIS_FINAL;

    if (mcx->script_out && result == MAVIS_FINAL)
	mavis_script_eval(mcx, *ac, mcx->script_out);

    Debug((DEBUG_MAVIS, "- %s = %d\n", __func__, result));
    return result;
}
Пример #3
0
static int Mavis_init(mavis_ctx * mcx)
{
    int result = MAVIS_INIT_OK;
#ifdef HAVE_mavis_init_out
    int tmp_result = MAVIS_INIT_OK;
#endif
    DebugIn(DEBUG_MAVIS);

    mavis_check_version(VERSION);

#ifdef HAVE_mavis_init_in
    result = mavis_init_in(mcx);
#endif

    if (mcx->down)
	result = mcx->down->init(mcx->down);

#ifdef HAVE_mavis_init_out
    tmp_result = mavis_init_out(mcx);
    if (result == MAVIS_INIT_OK)
	result = tmp_result;
#endif

    Debug((DEBUG_MAVIS, "- %s = %d\n", __func__, result));
    return result;
}
Пример #4
0
void h_user(struct context *ctx, char *arg)
{
    char *host;

    DebugIn(DEBUG_COMMAND);

    if (ctx->state == ST_conn) {
	ctx->state = ST_user;

	host = strchr(arg, '@');
	if (host) {
	    *host++ = 0;
	    strset(&ctx->vhost, host);
	}

	if (!strcasecmp(arg, "ftp") || !strcasecmp(arg, "anonymous")) {
	    reply(ctx, MSG_331_anon);
	    strset(&ctx->user, "ftp");
	    ctx->anonymous = 1;
	} else {
	    reply(ctx, MSG_331_user);
	    strset(&ctx->user, arg);
	    ctx->anonymous = 0;
	}
    } else
	reply(ctx, MSG_503_Already_logged_in);

    DebugOut(DEBUG_COMMAND);
}
Пример #5
0
static int mavis_send_in(mavis_ctx * mcx, av_ctx ** ac)
{
    char *t, *u;
    DebugIn(DEBUG_MAVIS);
    t = av_get(*ac, AV_A_TYPE);
    u = av_get(*ac, AV_A_USER);
    if (strcmp(t, AV_V_TYPE_FTP)
	|| (strcasecmp(u, "ftp")
	    && strcasecmp(u, "anonymous"))) {
	Debug((DEBUG_MAVIS, "- %s = MAVIS_DOWN (no anon ftp)\n", __func__));
	return MAVIS_DOWN;
    }

    av_set(*ac, AV_A_RESULT, AV_V_RESULT_OK);
    av_setf(*ac, AV_A_UID, "%d", (int) mcx->uid);
    av_setf(*ac, AV_A_GID, "%d", (int) mcx->gid);
    av_set(*ac, AV_A_HOME, mcx->home);
    av_set(*ac, AV_A_ROOT, mcx->root);
    av_set(*ac, AV_A_FTP_ANONYMOUS, AV_V_BOOL_TRUE);
    if (mcx->incoming)
	av_set(*ac, AV_A_ANON_INCOMING, mcx->incoming);
    if ((t = av_get(*ac, AV_A_PASSWORD)))
	av_set(*ac, AV_A_EMAIL, t);
    Debug((DEBUG_MAVIS, "- %s = MAVIS_FINAL\n", __func__));
    return MAVIS_FINAL;
}
Пример #6
0
static int mavis_init_in(mavis_ctx * mcx)
{
    int i;

    DebugIn(DEBUG_MAVIS);

    mcx->lastdump = mcx->startup_time = time(NULL);

    if (!mcx->path)
	logmsg("Warning: %s: module lacks path definition", MAVIS_name);
    else if (!mcx->argv[0]) {
	mcx->argv[0] = Xstrdup(basename(mcx->path));
	mcx->argv[1] = NULL;
    }

    if (mcx->child_min > mcx->child_max)
	mcx->child_min = mcx->child_max;

    if (!mcx->io_context_parent)
	mcx->io_context_local = mcx->io = io_init();
    mcx->cx = Xcalloc(mcx->child_max, sizeof(struct context *));
    mcx->cx_stat = Xcalloc(mcx->child_max, sizeof(struct context_stat));
    for (i = 0; i < mcx->child_min; i++)
	fork_child(mcx, i);

    mcx->backlog_serial = RB_tree_new(compare_serial, NULL);
    mcx->backlog_app_ctx = RB_tree_new(compare_app_ctx, NULL);
    mcx->backlog_fifo = RB_tree_new(compare_fifo, free_payload);
    mcx->outgoing = RB_tree_new(compare_app_ctx, free_payload);
    mcx->junkcontexts = RB_tree_new(compare_ctx, free_context);

    DebugOut(DEBUG_MAVIS);
    return MAVIS_INIT_OK;
}
Пример #7
0
static void getchecksum(struct context *ctx)
{
    size_t len;
    struct md_method *m = ctx->md_hash ? ctx->md_method_hash : ctx->md_method_checksum;

    DebugIn(DEBUG_BUFFER);

    sigbus_cur = ctx->cfn;

    if (chunk_get(ctx, &ctx->io_offset)) {
	reply(ctx, MSG_451_Internal_error);
	goto bye;
    }

    if (chunk_remaining(ctx)) {
	len = MIN((size_t) bufsize, ctx->chunk_length);
	m->update(ctx, (u_char *) ctx->chunk_start, len);
	chunk_release(ctx, len);
    }

    if (chunk_remaining(ctx))
	io_sched_renew_proc(ctx->io, ctx, (void *) getchecksum);
    else {
	if (!strcmp(m->ftp_name, "CRC32")) {
	    if (ctx->md_hash) {
		replyf(ctx, "213 %s %llu-%llu %s %s\r\n", m->ftp_name,
		       (unsigned long long) ctx->io_offset_start, (unsigned long long) ctx->offset, m->final(ctx), ctx->filename + ctx->rootlen);
	    } else
		replyf(ctx, "200 %s %llu %s\r\n", m->final(ctx), (unsigned long long) ctx->offset, ctx->filename + ctx->rootlen);
	} else if (ctx->md_hash) {
Пример #8
0
static void child_died(struct context *ctx, int cur __attribute__ ((unused)))
{
    if (ctx->ac) {		// might be called multiple times else
	int i = ctx->index;
	DebugIn(DEBUG_PROC);

	if (ctx->mcx->cx[i]->counter < 2) {
	    logmsg("%s: %lu: terminated before finishing first request", ctx->mcx->argv[0], (u_long) ctx->pid);
	    ctx->mcx->reaphist[ctx->mcx->reapcur] = io_now.tv_sec + REAPINT;
	    ctx->mcx->reapcur++;
	    ctx->mcx->reapcur %= REAPMAX;
	    ctx->mcx->usage--;
	} else
	    logmsg("%s: %lu: terminated after processing %llu requests", ctx->mcx->argv[0], (u_long) ctx->pid, ctx->mcx->cx[i]->counter);

	ctx->mcx->cx[i]->counter = 0;

	io_child_set(ctx->pid, NULL, NULL);

	if (ctx->fd_in > -1) {
	    io_close(ctx->mcx->io, ctx->fd_in);
	    ctx->fd_in = -1;
	}
	if (ctx->fd_out > -1) {
	    io_close(ctx->mcx->io, ctx->fd_out);
	    ctx->fd_out = -1;
	}

	ctx->index = -1;

	RB_insert(ctx->mcx->junkcontexts, ctx);

#ifdef DEBUG_RB
	fprintf(stderr, "EXT insert junkcontexts %p\n", ctx);
#endif

	ctx->mcx->cx[i] = NULL;
	ctx->mcx->child_cur--;

	fork_child(ctx->mcx, i);

	if (ctx->mcx->cx[i]) {
	    ctx->mcx->cx[i]->ac = ctx->ac;
	    ctx->ac = NULL;

	    ctx->mcx->cx_stat[i].counter++;
	    ctx->mcx->cx_stat[i].counter_p++;
	    start_query(ctx->mcx->cx[i]);
	}

	DebugOut(DEBUG_PROC);
    }
}
Пример #9
0
static void skipbytes(struct context *ctx, int cur __attribute__ ((unused)))
{
    off_t ro = ctx->io_offset, off = 0;

    DebugIn(DEBUG_BUFFER);

    sigbus_cur = ctx->cfn;

    if (chunk_get(ctx, NULL)) {
	io_sched_pop(ctx->io, ctx);
	ctx->dbufi = buffer_free_all(ctx->dbufi);
	ctx->remaining = 0, ctx->offset = 0;
	cleanup_file(ctx, ctx->ffn);
	cleanup_data(ctx, ctx->ffn);
	reply(ctx, MSG_451_Internal_error);
    } else {
	if (chunk_remaining(ctx)) {
	    char *u = ctx->chunk_start;
	    char lastchar = ctx->lastchar;
	    size_t len = MIN(ctx->chunk_length, (size_t) bufsize);
	    char *ul = u + len;

	    for (off = 0; ro && u < ul; ro--, off++, lastchar = *u++)
		if (*u == '\n' && lastchar != '\r')
		    ro--;

	    ctx->lastchar = lastchar;
	    chunk_release(ctx, len);
	}

	if (!chunk_remaining(ctx))
	    ro = 0;

	if (!ro) {
	    ctx->dbufi = buffer_free_all(ctx->dbufi);
	    lseek(ctx->ffn, ctx->offset + off, SEEK_SET);
	    ctx->remaining = 0, ctx->offset = 0;

	    if (io_get_cb_i(ctx->io, ctx->dfn) == (void *) socket2buffer) {
		/* already connected */
		io_clr_o(ctx->io, ctx->dfn);
		io_set_i(ctx->io, ctx->dfn);
	    }
	    io_sched_pop(ctx->io, ctx);
	} else
	    io_sched_renew_proc(ctx->io, ctx, (void *) skipbytes);

	ctx->io_offset = ro;
    }

    DebugOut(DEBUG_BUFFER);
}
Пример #10
0
void h_pass(struct context *ctx, char *arg)
{
    DebugIn(DEBUG_COMMAND);

    if (ctx->state == ST_user) {
	if (arg[0] == '-')
	    ctx->multiline_banners = 0;
	auth_mavis(ctx, arg);
    } else
	reply(ctx, MSG_503_USER_before_PASS);

    DebugOut(DEBUG_COMMAND);
}
Пример #11
0
static int mavis_init_in(mavis_ctx * mcx)
{
    DebugIn(DEBUG_MAVIS);
    if (!mcx->initialized) {
	mcx->initialized++;
	if (!mcx->service)
	    mcx->service = Xstrdup("mavis");
	if (geteuid())
	    logmsg("Warning: PAM module may require root privileges");
    }
    DebugOut(DEBUG_MAVIS);
    return MAVIS_INIT_OK;
}
Пример #12
0
void h_mfmt(struct context *ctx, char *arg)
{
    char *t;
    struct stat st;
    struct tm tm;

    DebugIn(DEBUG_COMMAND);

    t = arg;

    while (*arg && !isspace((int) *arg))
	arg++;

    if (!isspace((int) *arg)) {
	reply(ctx, MSG_500_arguments_required);
	DebugOut(DEBUG_COMMAND);
	return;
    }

    memset(&tm, 0, sizeof(tm));
    *arg++ = 0;

    if (*arg && 6 == sscanf(t, "%4d%2d%2d%2d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec)) {
	struct utimbuf ut;
	tm.tm_year -= 1900;
	tm.tm_mon--;
	ut.modtime = mktime(&tm);

	if ((t = buildpath(ctx, arg)) && (!pickystat(ctx, &st, t))
	    && (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
	    && st.st_uid == ctx->uid) {
	    ut.actime = st.st_atime;
	    if (utime(t, &ut))
		reply(ctx, MSG_550_Permission_denied);
	    else {
		struct stat sst;
		char u[40];
		if (stat(t, &sst))
		    sst.st_mtime = ut.modtime;
		strftime(u, sizeof(u), "213 Modify=%Y%m%d%H%M%S; ", gmtime(&sst.st_mtime));
		replyf(ctx, "%s%s\r\n", u, t);
	    }
	} else
	    reply(ctx, MSG_550_Permission_denied);
    } else
	reply(ctx, MSG_500_missing_filename);

    DebugOut(DEBUG_COMMAND);
}
Пример #13
0
static int Mavis_send(mavis_ctx * mcx, av_ctx ** ac)
{
    int result = MAVIS_DOWN;

    DebugIn(DEBUG_MAVIS);

    if (mcx->ac_bak_required) {
	if (!mcx->ac_bak)
	    mcx->ac_bak = av_new(NULL, NULL);
	av_copy(mcx->ac_bak, *ac);
    }

    if (mcx->script_in) {
	switch (mavis_script_eval(mcx, *ac, mcx->script_in)) {
	case S_skip:
	    break;
	case S_return:
	    if (mcx->script_out)
		mavis_script_eval(mcx, *ac, mcx->script_out);
	    return MAVIS_FINAL;
	default:;
#ifdef HAVE_mavis_send_in
	    result = mavis_send_in(mcx, ac);
#endif
	}
    }
#ifdef HAVE_mavis_send_in
    else
	result = mavis_send_in(mcx, ac);
#endif

    if (result == MAVIS_DOWN && mcx->down)
	result = mcx->down->send(mcx->down, ac);

#ifdef HAVE_mavis_recv_out
    if (result == MAVIS_FINAL)
	result = mavis_recv_out(mcx, ac);
#endif

    if (result == MAVIS_DOWN)
	result = MAVIS_FINAL;

    if (mcx->script_out && result == MAVIS_FINAL)
	mavis_script_eval(mcx, *ac, mcx->script_out);

    Debug((DEBUG_MAVIS, "- %s = %d\n", __func__, result));
    return result;
}
Пример #14
0
void replyf(struct context *ctx, char *format, ...)
{
    ssize_t len = 1024, nlen;
    size_t j = 2 * len;
    char *tmpbuf;

    DebugIn(DEBUG_PROC);

  again:
    tmpbuf = alloca(j);

    if (ctx && ctx->cfn > -1) {
	va_list ap;
	va_start(ap, format);
	nlen = vsnprintf(tmpbuf, len, format, ap);
	va_end(ap);
	if (len <= nlen) {
	    j = 2 * ++nlen;
	    goto again;
	}
	len = nlen;

	if (len > -1) {
	    char *t = tmpbuf + len - 1;
	    char *u = tmpbuf + 2 * len - 1;
	    ssize_t f;

	    /* <CR><NL> at the end of the format string is ok */
	    if (len > 1 && ((f = strlen(format)) > 1)
		&& format[f - 2] == '\r' && format[f - 1] == '\n') {
		*u-- = *t--;
		*u-- = *t--;
	    }

	    for (; t >= tmpbuf; *u-- = *t--)
		if (*t == '\r')
		    /* <CR> => <CR><NUL> */
		    *u-- = 0, len++;
		else if ((u_char) * t == IAC)
		    /* <IAC> => <IAC><IAC> */
		    *u-- = IAC, len++;
	    ctx->cbufo = buffer_write(ctx->cbufo, u + 1, len);

	    io_set_o(ctx->io, ctx->cfn);
	}
    }
    DebugOut(DEBUG_PROC);
}
Пример #15
0
void reply(struct context *ctx, char *s)
{
    DebugIn(DEBUG_PROC);

    if (ctx && ctx->cfn > -1) {
	size_t len = strlen(s);
	if (len > 1 && s[len - 2] == '\r' && s[len - 1] == '\n') {
	    /* Don't escape <CR><LF> at end of string */
	    ctx->cbufo = buffer_reply(ctx->cbufo, s, len - 2);
	    ctx->cbufo = buffer_write(ctx->cbufo, "\r\n", 2);
	} else
	    ctx->cbufo = buffer_reply(ctx->cbufo, s, len);

	io_set_o(ctx->io, ctx->cfn);
    }
    DebugOut(DEBUG_PROC);
}
Пример #16
0
static int Mavis_cancel(mavis_ctx * mcx, void *app_ctx)
{
    int result = MAVIS_DOWN;

    DebugIn(DEBUG_MAVIS);

#ifdef HAVE_mavis_cancel_in
    result = mavis_cancel_in(mcx, app_ctx);
#endif

    if (result == MAVIS_DOWN && mcx->down)
	result = mcx->down->cancel(mcx->down, app_ctx);

    if (result == MAVIS_DOWN)
	result = MAVIS_FINAL;

    Debug((DEBUG_MAVIS, "- %s = %d\n", __func__, result));
    return result;
}
Пример #17
0
struct buffer *buffer_reply(struct buffer *b, char *s, size_t len)
{
    size_t j = 2 * len;
    char *a = alloca(j);
    char *t = a, *se = s + len;
    DebugIn(DEBUG_PROC);

    for (; s < se; s++) {
	*t++ = *s;
	if (*s == '\r')
	    /* <CR> => <CR><NUL> */
	    *t++ = 0, len++;
	else if ((u_char) * s == IAC)
	    *t++ = IAC, len++;
    }
    b = buffer_write(b, a, len);
    DebugOut(DEBUG_PROC);
    return b;
}
Пример #18
0
static int Mavis_parse(mavis_ctx * mcx, struct sym *sym, char *id)
{
    int result = MAVIS_CONF_ERR;
    DebugIn(DEBUG_MAVIS);

#ifdef HAVE_mavis_parse_in
    if (!strcmp(id, mcx->identifier))
	result = mavis_parse_in(mcx, sym);
    else
#endif
    if (mcx->down) {
	result = mcx->down->parse(mcx->down, sym, id);
	if (result != MAVIS_CONF_OK)
	    result = MAVIS_CONF_ERR;
    }

    Debug((DEBUG_MAVIS, "- %s = %d\n", __func__, result));
    return result;
}
Пример #19
0
static int mavis_init_in(mavis_ctx * mcx)
{
    DebugIn(DEBUG_MAVIS);
    if (!mcx->initialized) {
	mcx->initialized++;
	if (mcx->require_valid_shell && !mcx->shellpath)
	    mcx->shellpath = Xstrdup("/etc/shells");
	if (mcx->honour_ftpusers && !mcx->ftpuserspath)
	    mcx->ftpuserspath = Xstrdup("/etc/ftpusers");
	if (mcx->lookup_sslusers && !mcx->ssluserspath)
	    mcx->ssluserspath = Xstrdup("/etc/ssl.users");
	if (geteuid())
	    logmsg("Warning: SYSTEM module requires root privileges");
#ifdef NOTHING // WITH_LIBCRYPT
	/* We need to make sure to get crypt(3) from libcrypt.so, not from
	 * the OpenSSL libcrypto.so library, which may be already loaded.
	 * Reason for that is that the libcrypt version may support additional
	 * encryption algorithms, e.g. MD5.
	 */
	mcx->libcrypt = dlopen("libcrypt.so", RTLD_LAZY);
	if (mcx->libcrypt) {
	    mcx->crypt = (char *(*)(const char *, const char *))
		dlsym(mcx->libcrypt, DLSYM_PREFIX "crypt");
	    if (!mcx->crypt) {
		dlclose(mcx->libcrypt);
		mcx->libcrypt = NULL;
		mcx->crypt = crypt;
	    }
	}
	if (!mcx->crypt)
#endif
	    mcx->crypt = crypt;
    }
    DebugOut(DEBUG_MAVIS);
    return MAVIS_INIT_OK;
}
Пример #20
0
void h_rnfr(struct context *ctx, char *arg)
{
    char *t;
    struct stat st;

    DebugIn(DEBUG_COMMAND);

    if ((t = buildpath(ctx, arg)) && (strlen(t) > ctx->rootlen) && (!pickystat(ctx, &st, t)) && (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))) {
	ctx->last_command_was_rnfr = 1;

	if (strlen(t) >= sizeof(ctx->filename)) {
	    logerr("buffer too small in %s:%d (%s/%s)", __FILE__, __LINE__, ctx->user, t);
	    reply(ctx, MSG_551_Internal_error);
	    cleanup_data(ctx, ctx->dfn);
	    DebugOut(DEBUG_COMMAND);
	    return;
	}
	strcpy(ctx->filename, t);
	reply(ctx, MSG_350_Awaiting_dest);
    } else
	reply(ctx, MSG_550_No_such_file);

    DebugOut(DEBUG_COMMAND);
}
Пример #21
0
void h_stor(struct context *ctx, char *arg)
{
    DebugIn(DEBUG_COMMAND);
    h_xstor(ctx, arg, (ctx->io_offset ? 0 : O_TRUNC));
    DebugOut(DEBUG_COMMAND);
}
Пример #22
0
static void read_from_child(struct context *ctx, int cur)
{
    ssize_t len;
    DebugIn(DEBUG_MAVIS);

    len = Read(ctx->fd_in, ctx->b_in + ctx->b_in_len, sizeof(ctx->b_in) - ctx->b_in_len - 1);

    if (len > 0) {
	char *t;
	int matchlevel = 0;

	Debug((DEBUG_PROC, "%s:%d %s\n", __FILE__, __LINE__, ctx->mcx->path));
	ctx->b_in_len += len;
	ctx->b_in[ctx->b_in_len] = 0;

	for (t = ctx->b_in + ctx->b_in_len - 1; t > ctx->b_in; t--)
	    switch (matchlevel) {
	    case 0:
		if (*t != '\n') {
		    DebugOut(DEBUG_MAVIS);
		    return;
		}
		matchlevel++;
		break;
	    case 1:
		if (!isdigit((int) *t)) {
		    DebugOut(DEBUG_MAVIS);
		    return;
		}
		matchlevel++;
		break;
	    case 2:
		if (!isdigit((int) *t) && *t != '-' && *t != '=') {
		    DebugOut(DEBUG_MAVIS);
		    return;
		}
		if (*t == '=')
		    matchlevel++;
		break;
	    case 3:
		if (*t == '\n') {
		    rb_node_t *r;
		    struct query *q;
		    char *serial = av_get(ctx->ac, AV_A_SERIAL);
		    char *serial_old = alloca(strlen(serial) + 1);
		    int result;

		    strcpy(serial_old, serial);

		    io_clr_i(ctx->mcx->io, ctx->fd_in);

		    av_clear(ctx->ac);
		    *++t = 0;
		    av_char_to_array(ctx->ac, ctx->b_in, NULL);
		    result = atoi(++t);

		    ctx->in_use = 0;
		    ctx->mcx->usage--;

		    serial = av_get(ctx->ac, AV_A_SERIAL);

		    if (!serial || strcmp(serial, serial_old)) {
			if (serial)
			    logmsg("%s: %lu: out of sync: " "got %s, expected %s. Terminating.", ctx->mcx->argv[0], (u_long) ctx->pid, serial, serial_old);
			else
			    logmsg("%s: %lu: missing serial. Terminating.", ctx->mcx->argv[0], (u_long) ctx->pid);
			av_free(ctx->ac);
			ctx->ac = NULL;
			kill(ctx->pid, SIGTERM);
			child_died(ctx, ctx->fd_in);
			DebugOut(DEBUG_MAVIS);
			return;
		    }

		    q = Xcalloc(1, sizeof(struct context));
		    q->ac = ctx->ac;
		    ctx->ac = NULL;

		    q->result = result;

		    q->canceled = ctx->canceled;
		    ctx->canceled = 0;

		    RB_insert(ctx->mcx->outgoing, q);
#ifdef DEBUG_RB
		    fprintf(stderr, "EXT insert outgoing %p\n", q);
#endif

		    if (ctx->mcx->io_context_parent) {
			if (!RB_empty(ctx->mcx->backlog_fifo)) {
			    rb_node_t *rbn = RB_first(ctx->mcx->backlog_fifo);
			    struct query *qp = RB_payload(rbn, struct query *);
			    Debug((DEBUG_PROC, "%s:%d\n", __FILE__, __LINE__));
			    RB_search_and_delete(ctx->mcx->backlog_app_ctx, qp);
			    RB_search_and_delete(ctx->mcx->backlog_serial, qp);
			    ctx->ac = qp->ac;
			    qp->ac = NULL;
			    RB_delete(ctx->mcx->backlog_fifo, rbn);
#ifdef DEBUG_RB
			    fprintf(stderr, "EXT remove backlog_fifo %p\n", RB_payload(rbn, void *));
#endif
			    ctx->mcx->backlog_cur--;
			    ctx->mcx->usage++;
			    ctx->mcx->cx_stat[ctx->index].counter++;
			    ctx->mcx->cx_stat[ctx->index].counter_p++;
			    start_query(ctx);
			}

			while ((r = RB_first(ctx->mcx->outgoing))) {
			    struct query *qp = RB_payload(r, struct query *);

			    if (ctx->mcx->ac_bak)
				av_free(ctx->mcx->ac_bak);
			    ctx->mcx->ac_bak = qp->ac_bak;
			    qp->ac_bak = NULL;

			    if (q->canceled) {
				av_free(ctx->mcx->ac_bak);
				ctx->mcx->ac_bak = NULL;
				RB_delete(ctx->mcx->outgoing, r);
			    } else
				((void (*)(void *)) qp->ac->app_cb) (qp->ac->app_ctx);
			}
		    }
		    DebugOut(DEBUG_MAVIS);
		    return;
		}
Пример #23
0
static void h_xstor(struct context *ctx, char *arg, int flags)
{
    char *t;
    int f = -1;
    struct stat st;
    int stou = 0;
    char tbuf[PATH_MAX + 1];

    DebugIn(DEBUG_COMMAND);

    if (ctx->transfer_in_progress) {
	reply(ctx, MSG_501_Transfer_in_progress);
	DebugOut(DEBUG_COMMAND);
	return;
    }

    ctx->outgoing_data = 0;
    if (ctx->dfn > -1 && io_get_cb_i(ctx->io, ctx->dfn) == (void *) accept_data) {
	io_set_i(ctx->io, ctx->dfn);
	io_clr_o(ctx->io, ctx->dfn);
	io_set_cb_e(ctx->io, ctx->dfn, (void *) cleanup_data);
	io_set_cb_h(ctx->io, ctx->dfn, (void *) cleanup_data);
    }

    quota_add(ctx, 0);

    if (ctx->quota_path && (ctx->quota_ondisk >= ctx->quota_limit)) {
	reply(ctx, MSG_451_quota_exceeded);
	logmsg("%s: quota limit reached", ctx->user);
	DebugOut(DEBUG_COMMAND);
	return;
    }

    if (!arg) {
	stou = -1;
	snprintf(tbuf, sizeof(tbuf), "%s/stou.XXXXXX", ctx->cwd);
	arg = tbuf;

	t = buildpath(ctx, arg);
    } else if (acl_binary_only(ctx, arg, (t = buildpath(ctx, arg)))) {
	reply(ctx, MSG_504_no_ascii);
	cleanup_data_reuse(ctx, ctx->dfn);
	DebugOut(DEBUG_COMMAND);
	return;
    }

    st.st_size = 0;

    if (t)
	acl_set_umask(ctx, arg, t);

    if (ctx->anonymous || stou)
	flags |= O_EXCL;

    if (t && (!ctx->anonymous || check_incoming(ctx, t, 077)) &&
	!pickystat_path(ctx, &st, t) &&
	(stat(t, &st), (f = myopen(t, O_RDWR | O_CREAT | O_LARGEFILE | O_NOFOLLOW | flags, ctx->chmod_filemask | (0644 & ~ctx->umask), stou)) > -1)) {

	fcntl(f, F_SETFD, FD_CLOEXEC);

	ctx->quota_filesize_before_stor = st.st_size;
	ctx->quota_update_on_close = 1;

	if (ctx->dfn < 0)
	    connect_port(ctx);

	if (ctx->dfn < 0) {
	    reply(ctx, MSG_431_Opening_datacon_failed);
	    close(f);
	    ctx->dbuf = buffer_free_all(ctx->dbuf);
	    DebugOut(DEBUG_COMMAND);
	    return;
	}

	ctx->ffn = f;
	if (strlen(t) >= sizeof(ctx->filename)) {
	    logerr("buffer too small in %s:%d (%s/%s)", __FILE__, __LINE__, ctx->user, t);
	    reply(ctx, MSG_551_Internal_error);
	    close(f);
	    cleanup(ctx, ctx->dfn);
	    ctx->dbuf = buffer_free_all(ctx->dbuf);
	    DebugOut(DEBUG_COMMAND);
	    return;
	}
	strcpy(ctx->filename, t);
	ctx->filesize = 0;
	ctx->bytecount = 0;

	if (io_get_cb_i(ctx->io, ctx->dfn) == (void *) socket2buffer || is_connected(ctx->dfn)) {
	    if (stou)
		replyf(ctx, "125 FILE: %s\r\n", ctx->filename + ctx->rootlen);
	    else
		replyf(ctx, MSG_125_Starting_dc, ctx->use_ascii ? "ASCII" : "BINARY", ctx->use_tls_d ? "TLS " : "");
	} else {
	    if (stou)
		replyf(ctx, "150 FILE: %s\r\n", ctx->filename + ctx->rootlen);
	    else
		replyf(ctx, MSG_150_Opening_dc, ctx->use_ascii ? "ASCII" : "BINARY", ctx->use_tls_d ? "TLS " : "");
	}

	ctx->transfer_in_progress = 1;

	if (ctx->io_offset) {
	    if (ctx->use_ascii) {
		ctx->offset = 0;
		ctx->remaining = st.st_size;
		io_sched_add(ctx->io, ctx, (void *) skipbytes, 0, 0);
#ifdef WITH_MMAP
		if (use_mmap)
		    ctx->iomode = IOMODE_mmap;
		else
#endif
		    ctx->iomode = IOMODE_read, ctx->iomode_fixed = 1;
	    } else {
		lseek(f, ctx->io_offset, SEEK_SET);
		ctx->io_offset = 0;
	    }
	}

	if (io_get_cb_i(ctx->io, ctx->dfn) == (void *) socket2buffer) {
	    /* already connected */
	    io_clr_o(ctx->io, ctx->dfn);
	    io_set_i(ctx->io, ctx->dfn);
	}

	ctx->transferstart = io_now.tv_sec;
	ctx->count_files++;
    } else {
	if (stou && errno == EEXIST)
	    reply(ctx, MSG_451_unique_file_failure);
	else
	    reply(ctx, MSG_550_Permission_denied);
	cleanup_data_reuse(ctx, ctx->dfn);
    }

    DebugOut(DEBUG_COMMAND);
}
Пример #24
0
void ident_socket2buffer(struct context *ctx, int cur)
{
    ssize_t l;

    DebugIn(DEBUG_NET);

    l = read(cur, ctx->ident_buf + ctx->ident_buflen, MAXBUFSIZE1413 - ctx->ident_buflen - 1);

    if (l > 0) {
	char *t;

	ctx->ident_buflen += l;
	ctx->ident_buf[ctx->ident_buflen] = 0;
	if ((t = strstr(ctx->ident_buf, "\r\n"))) {
	    int rp, lp;
	    *t = 0;
	    Debug((DEBUG_PROC, "RFC1413 answer: \"%s\"\n", ctx->ident_buf));

	    if (2 == sscanf(ctx->ident_buf, " %d , %d :", &rp, &lp) && su_get_port(&ctx->sa_c_local) == lp && su_get_port(&ctx->sa_c_remote) == rp) {
		char buf[160];
		char *u = rfc2428_str(&ctx->sa_c_remote, buf, sizeof(buf));
		if (u) {
		    t = alloca(strlen(u) + 1);
		    strcpy(t, u);
		}
		u = strchr(ctx->ident_buf, ':');
		if (u)
		    do
			u++;
		    while (*u && isspace((int) *u));

		if (ctx->loglevel & LOG_IDENT)
		    logmsg("%s->%s: %s", t ? t : "", rfc2428_str(&ctx->sa_c_local, buf, sizeof(buf)), u ? u : ctx->ident_buf);

		if (u && !strncasecmp("USERID", u, 6)) {
		    u += 6;
		    while (*u && isspace((int) *u))
			u++;
		    if (*u == ':') {
			do
			    u++;
			while (*u && *u != ':');
			if (*u) {
			    do
				u++;
			    while (*u && isspace((int) *u));
			    if (*u)
				strset(&ctx->ident_user, u);
			}
		    }
		}
	    }

	    cleanup_ident(ctx, cur);
	} else if (ctx->ident_buflen == MAXBUFSIZE1413 - 1)	/* response too long */
	    cleanup_ident(ctx, cur);
    } else if (!l || (l < 0 && errno != EAGAIN))
	cleanup_ident(ctx, cur);

    DebugOut(DEBUG_NET);
}
Пример #25
0
static void parsecmd(struct context *ctx, int cfn)
{
    char *t, *u;
    char lastchar = 0;		/* Anything different from <CR> will do. */
    DebugIn(DEBUG_PROC);

    t = u = ctx->cbufi->buf + ctx->cbufi->offset;

  again:

    for (; t < ctx->cbufi->buf + ctx->cbufi->length; t++)
	switch (*t) {
	case '\0':
	    if (lastchar == '\r')	/* <CR><NUL> => <CR> */
		lastchar = *u++ = *t;
	    else {
		Debug((DEBUG_PROC, " %s: Illegal character sequence \\%o\\%o\n", __func__, lastchar, *t));
		cleanup(ctx, ctx->cfn);
		DebugOut(DEBUG_PROC);
		return;
	    }
	    break;
	case '\n':
	    if (lastchar == '\r') {	/* <CR><LF> => EOL */
		struct io_context *io = ctx->io;
		cfn = ctx->cfn;
		*(u - 1) = 0;
		checkcmd(ctx, ctx->cbufi->buf);

		if (io_get_ctx(io, cfn))
		    /* need to check whether our context is still valid */
		{
		    ctx->cbufi->offset = t - ctx->cbufi->buf + 1;
		    if (ctx->cbufi->offset == ctx->cbufi->length) {
			ctx->cbufi = buffer_free(ctx->cbufi);
			io_sched_del(ctx->io, ctx, (void *) parsecmd);
			if (!ctx->cbufi && io_get_cb_i(ctx->io, ctx->cfn) == (void *) readcmd)
			    io_set_i(ctx->io, ctx->cfn);
		    } else if (io_sched_renew_proc(ctx->io, ctx, (void *) parsecmd))
			io_sched_add(ctx->io, ctx, (void *) parsecmd, 0, 0);
		}
		DebugOut(DEBUG_PROC);
		return;
	    }
	    /* fall through */
	default:
	    lastchar = *u++ = *t;
	}

    /*
     * The FTP protocol doesn't support pipelining. No way this code can
     * be reached with a well-behaving client.
     */

    /*
     * Move content of input buffer to beginning of buffer.
     */
    if (ctx->cbufi->offset != ctx->cbufi->length) {
	ctx->cbufi->length -= ctx->cbufi->offset;
	memmove(ctx->cbufi->buf, ctx->cbufi->buf + ctx->cbufi->offset, ctx->cbufi->length);
	t -= ctx->cbufi->offset, u -= ctx->cbufi->offset;
	ctx->cbufi->offset = 0;
    }

    /*
     * If we have more data, try to fill current buffer, then continue parsing.
     */
    if (ctx->cbufi->next && ctx->cbufi->length < ctx->cbufi->size) {
	size_t len = MIN(ctx->cbufi->size - ctx->cbufi->length,
			 ctx->cbufi->next->length - ctx->cbufi->offset);
	memcpy(ctx->cbufi->buf + ctx->cbufi->length, ctx->cbufi->next->buf + ctx->cbufi->offset, len);
	ctx->cbufi->length += len, ctx->cbufi->next->offset += len;
	if (ctx->cbufi->next->offset == ctx->cbufi->next->length)
	    ctx->cbufi->next = buffer_free(ctx->cbufi->next);
	goto again;
    }

    /*
     * Terminate connection if buffer filled but no <CR><LF> is found.
     * Otherwise, accept more input.
     */
    if (ctx->cbufi->length == ctx->cbufi->size) {
	logmsg("Found garbage in command buffer. Terminating session %.8lx", ctx->id);
	cleanup(ctx, ctx->cfn);
    } else
	io_set_i(ctx->io, ctx->cfn);

    DebugOut(DEBUG_PROC);
}
Пример #26
0
void h_site_chmod(struct context *ctx, char *arg)
{
    char *t;
    struct stat st;
    u_int mode;
    u_int mode_add = 0;
    u_int mode_del = 0;
    int numeric = -1;

    DebugIn(DEBUG_COMMAND);

    t = arg;

    while (*arg && !isspace((int) *arg))
	arg++;

    if (!isspace((int) *arg)) {
	reply(ctx, MSG_500_arguments_required);
	DebugOut(DEBUG_COMMAND);
	return;
    }

    *arg++ = 0;

    if (1 != sscanf(t, "%o", &mode)) {
	numeric = 0;
	mode = 0;
	while (*t) {
	    u_int bits_affected = 0;
	    u_int new_mode = 0;
	    char op = 0;

	    for (; *t && *t != ','; t++)
		if (op)
		    switch (*t) {
		    case 'r':
			new_mode |= 0444;
			break;
		    case 'w':
			new_mode |= 0222;
			break;
		    case 'x':
			new_mode |= 0111;
			break;
		    default:
		      invalid_mode:
			reply(ctx, MSG_500_invalid_mode);
			DebugOut(DEBUG_COMMAND);
			return;
		} else
		    switch (*t) {
		    case '+':
		    case '-':
		    case '=':
			op = *t;
			if (!bits_affected)
			    bits_affected = ~ctx->umask & 0777;
			break;
		    case 'u':
			bits_affected |= 0700;
			break;
		    case 'g':
			bits_affected |= 070;
			break;
		    case 'o':
			bits_affected |= 07;
			break;
		    case 'a':
			bits_affected = 0777;
			break;
		    default:
			goto invalid_mode;
		    }

	    new_mode &= bits_affected;
	    switch (op) {
	    case '+':
		mode_add |= new_mode;
		mode_del &= ~new_mode;
		break;
	    case '-':
		mode_del |= new_mode;
		mode_add &= ~new_mode;
		break;
	    case '=':
		mode_add |= new_mode;
		mode_del &= ~new_mode;
		mode_del |= ~new_mode & bits_affected;
		break;
	    default:
		goto invalid_mode;
	    }
	    if (*t)
		t++;
	}
    }

    while (isspace((int) *arg))
	arg++;

    if (!*arg)
	reply(ctx, MSG_500_missing_filename);
    else if ((t = buildpath(ctx, arg)) &&
	     !pickystat(ctx, &st, t) &&
	     (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) &&
	     !chmod(t, numeric ? mode : ((st.st_mode & ~mode_del) | mode_add) | (st.st_mode & (S_ISDIR(st.st_mode)
											       ? ctx->chmod_dirmask : ctx->chmod_filemask))))
	reply(ctx, MSG_200_permissions_changed);
    else
	reply(ctx, MSG_550_Permission_denied);

    DebugOut(DEBUG_COMMAND);
}