Exemple #1
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;
}
Exemple #2
0
static void mavis_io(struct context *ctx)
{
    av_ctx *avc = NULL;
    struct query *q;
    rb_node_t *r;
    char *serial;

    Debug((DEBUG_PROC, "mavis_io %p\n", ctx));
    switch (mavis_recv(mcx, &avc, ctx)) {
    case MAVIS_FINAL:
	break;
    case MAVIS_TIMEOUT:
	counter_expired++, counter_p_expired++;
    default:
	return;
    }

    if (!(serial = av_get(avc, AV_A_SERIAL)))
	return;

    q = alloca(sizeof(struct query));
    q->serial = serial;
    q->serial_crc = crc32_update(INITCRC32, (u_char *) serial, strlen(serial));

    if (!(r = RB_search(deferred_by_serial, q)))
	return;

    q = RB_payload(r, struct query *);

/* XXX -- move the unset functionality to a separate module? */
    if (!transmit_password) {
	av_unset(avc, AV_A_PASSWORD);
	av_unset(avc, AV_A_DBPASSWORD);
    }

    ctx = io_get_ctx(io, q->fd);
/* Send answer to client */
    av_send(avc, q->fd, &q->sa, ctx->blowfish);

/* Remove query from deferred queue */
    RB_delete(deferred_by_serial, r);
    backlog--;
    setproctitle("%s: backlog: %d", common_data.progname, backlog);

    counter_answered++, counter_p_answered++;
    return;
}				/* if */
Exemple #3
0
static void find_ssluser(av_ctx * ac, int fn, char *user)
{
    char inbuf[8192];
    size_t offset = 0;
    ssize_t inlength;
    char *linestart = inbuf;
    char *lineend;

    while ((inlength = Read(fn, inbuf + offset, sizeof(inbuf) - 1 - offset)) > 0) {
	inlength += offset;
	inbuf[inlength] = 0;
	linestart = inbuf;

	while ((lineend = strchr(linestart, '\n'))) {
	    *lineend = 0;

	    if (*linestart != '#') {
		char *subj = strchr(linestart, ':');
		if (subj) {
		    char *s = linestart;
		    char *t;
		    *subj++ = 0;
		    for (t = strtok(s, ","); t; t = strtok(NULL, ","))
			if (!strcmp(user, t)) {
			    char *a = av_get(ac, AV_A_DBCERTSUBJ);
			    if (a)
				av_setf(ac, AV_A_DBCERTSUBJ, "%s\r%s", a, subj);
			    else
				av_set(ac, AV_A_DBCERTSUBJ, subj);
			    break /* out of for-loop */ ;
			}
		}
	    }

	    linestart = lineend + 1;
	}

	offset = inbuf + inlength - linestart;
	if (offset)
	    memmove(inbuf, linestart, offset);
    }
}
Exemple #4
0
static int mavis_send_in(mavis_ctx * mcx, av_ctx ** ac)
{
    struct passwd *pw;
    char *t, *u, *p, *m;
    char buf[1024];

    t = av_get(*ac, AV_A_TYPE);
    u = av_get(*ac, AV_A_USER);
    p = av_get(*ac, AV_A_PASSWORD);

    if (strcmp(t, AV_V_TYPE_FTP))
	return MAVIS_DOWN;

    /* no VHOST support yet */
    m = av_get(*ac, AV_A_FTP_ANONYMOUS);
    if (m && !strcmp(m, AV_V_BOOL_TRUE))
	return MAVIS_DOWN;

    if (mcx->honour_ftpusers && !valid_user(mcx, u)) {
	av_set(*ac, AV_A_COMMENT, "user found in ftpusers file");
	av_set(*ac, AV_A_RESULT, AV_V_RESULT_FAIL);
	return MAVIS_FINAL;
    }
#ifdef HAVE_SHADOWPWD
    if (!mcx->passwordfile) {
	struct spwd *spw;
	uid_t uid;

	uid = geteuid();
	seteuid(0);
	spw = getspnam(u);
	seteuid(uid);

	if (!spw)
	    return MAVIS_DOWN;

	if (strcmp(spw->sp_pwdp, mcx->crypt(p, spw->sp_pwdp))) {
	    av_set(*ac, AV_A_COMMENT, "password mismatch");
	    av_unset(*ac, AV_A_DBPASSWORD);
	} else
	    av_set(*ac, AV_A_DBPASSWORD, p);
	pw = getpwnam(u);

	if (!pw) {
	    av_set(*ac, AV_A_COMMENT, "user not found in password file");
	    av_set(*ac, AV_A_RESULT, AV_V_RESULT_FAIL);
	    return MAVIS_FINAL;
	}
    } else
#endif				/* HAVE_SHADOWPWD */
    {
	int f;

	f = open(mcx->passwordfile, O_RDONLY);
	if (f < 0) {
	    av_set(*ac, AV_A_COMMENT, "error opening password file");
	    av_set(*ac, AV_A_RESULT, AV_V_RESULT_ERROR);
	    return MAVIS_DOWN;
	}
	pw = get_pwent(mcx, f, u);
	close(f);

	if (!pw)
	    return MAVIS_DOWN;
#undef crypt			/* may be set by openssl include stuff */
	if (strcmp(pw->pw_passwd, mcx->crypt(p, pw->pw_passwd))) {
	    av_set(*ac, AV_A_COMMENT, "password mismatch");
	    av_unset(*ac, AV_A_DBPASSWORD);
	} else
	    av_set(*ac, AV_A_DBPASSWORD, p);
    }

    if (mcx->require_valid_shell && (!pw->pw_shell || !valid_shell(mcx, pw->pw_shell))) {
	av_set(*ac, AV_A_COMMENT, "invalid shell");
	av_set(*ac, AV_A_RESULT, AV_V_RESULT_FAIL);
	return MAVIS_FINAL;
    }
    if (!pw->pw_dir) {
	av_set(*ac, AV_A_COMMENT, "home dir not set");
	av_set(*ac, AV_A_RESULT, AV_V_RESULT_FAIL);
	return MAVIS_FINAL;
    }

    av_setf(*ac, AV_A_UID, "%lu", (u_long) pw->pw_uid);
    av_setf(*ac, AV_A_GID, "%lu", (u_long) pw->pw_gid);

    /* attempt to get supplemental groups */

    av_set(*ac, AV_A_GIDS, groups_getlist(pw->pw_name, pw->pw_gid, buf, sizeof(buf)));

    if (mcx->ftp_chroot) {
	char *tp = strstr(pw->pw_dir, "/./");
	if (tp) {
	    *tp = 0;
	    av_set(*ac, AV_A_HOME, tp + 2);
	} else
	    av_set(*ac, AV_A_HOME, "/");
	av_set(*ac, AV_A_ROOT, pw->pw_dir);
    } else {
	av_set(*ac, AV_A_HOME, pw->pw_dir);
	av_set(*ac, AV_A_ROOT, "/");
    }

    if (mcx->lookup_sslusers)
	lookup_ssluser(mcx, *ac, u);

    return MAVIS_FINAL;
}
Exemple #5
0
void client_io(struct context *ctx, int cur)
{
/* We have incoming data. */
    char *serial;
    int res;
    ssize_t buflen;
    sockaddr_union sa;
    socklen_t sinlen = (socklen_t) sizeof(sockaddr_union);
    char *avt;
    char buf[BUFSIZE_MAVIS];
    av_ctx *avc;
    static struct query *q = NULL;

    if (!q)
	q = Xcalloc(1, sizeof(struct query));

    Debug((DEBUG_PROC, "client_io\n"));

/* Receive request from client */
    buflen = recvfrom(cur, buf, sizeof(buf) - 1, 0, &sa.sa, &sinlen);
    if (buflen <= 0)
	return;

    buf[buflen] = 0;

/* Decode data, if neccessary */
    if (ctx->blowfish)
	blowfish_dec(ctx->blowfish, (a_char *) buf, buflen);

/* Check client IP address */
    res = acl_check(&sa);
    if (!res) {
	char ibuf[INET6_ADDRSTRLEN];
	logmsg("Ignoring query from %s", su_ntop(&sa, ibuf, (socklen_t) sizeof(ibuf)));
	return;
    }

    counter_query++, counter_p_query++;

    avc = av_new(NULL, NULL);
    av_char_to_array(avc, buf, NULL);
    serial = av_get(avc, AV_A_SERIAL);
    if (!serial) {
	char ibuf[INET6_ADDRSTRLEN];
	logmsg("query from %s lacks serial", su_ntop(&sa, ibuf, (socklen_t) sizeof(ibuf)));
	counter_err++, counter_p_err++;
	av_free(avc);
	return;
    }

    q->serial = serial;
    q->serial_crc = crc32_update(INITCRC32, (u_char *) serial, strlen(serial));

    if (RB_search(deferred_by_serial, q)) {
	char ibuf[INET6_ADDRSTRLEN];
	Debug((DEBUG_PROC, "Duplicate detected\n"));
	logmsg("Ignoring duplicate query from %s (backlog: %d)", su_ntop(&sa, ibuf, (socklen_t) sizeof(ibuf)), backlog);
	counter_retry++, counter_p_retry++;
	av_free(avc);
	return;
    }

    if (av_get(avc, AV_A_RESULT)) {
	char ibuf[INET6_ADDRSTRLEN];
	Debug((DEBUG_PROC, "AV_A_RESULT already set. Spoofing?\n"));
	logmsg("Ignoring query with pre-set result code " "from %s (backlog: %d)", su_ntop(&sa, ibuf, (socklen_t) sizeof(ibuf)), backlog);
	counter_err++, counter_p_err++;
	av_free(avc);
	return;
    }

    avt = av_get(avc, AV_A_TYPE);

    if (!avt || !strncmp(avt, AV_V_TYPE_PRIVATE_PREFIX, AV_V_TYPE_PRIVATE_PREFIX_LEN)) {
	counter_err++, counter_p_err++;
	av_free(avc);
	return;
    }

    av_setcb(avc, (void *) mavis_io, (void *) q);

    switch (mavis_send(mcx, &avc)) {
    case MAVIS_DEFERRED:
	Debug((DEBUG_PROC, "mavis_send yields DEFERRED\n"));
	q->sa = sa;
	q->fd = cur;
	q->serial = Xstrdup(serial);
	RB_insert(deferred_by_serial, q);
	q = NULL;
	backlog++;
	if (backlog > backlog_max)
	    backlog_max = backlog;
	if (backlog > backlog_max_p)
	    backlog_max_p = backlog;
	setproctitle("%s: backlog: %d", common_data.progname, backlog);
	return;
    case MAVIS_TIMEOUT:
	counter_expired++, counter_p_expired++;
	break;

    case MAVIS_FINAL:
	if (!transmit_password) {
	    av_unset(avc, AV_A_PASSWORD);
	    av_unset(avc, AV_A_DBPASSWORD);
	}
	av_send(avc, cur, &sa, ctx->blowfish);
	counter_answered++, counter_p_answered++;
    }

    av_free(avc);
}
Exemple #6
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;
		}
Exemple #7
0
static int mavis_send_in(mavis_ctx * mcx, av_ctx ** ac)
{
    struct passwd *pw;
    char *t, *u, *p, *m;
    uid_t uid;
    int res;

    t = av_get(*ac, AV_A_TYPE);
    u = av_get(*ac, AV_A_USER);
    p = av_get(*ac, AV_A_PASSWORD);

    if (strcmp(t, AV_V_TYPE_FTP))
	return MAVIS_DOWN;

/* no VHOST support yet */
    m = av_get(*ac, AV_A_FTP_ANONYMOUS);
    if (m && !strcmp(m, AV_V_BOOL_TRUE))
	return MAVIS_DOWN;

    if (!(pw = getpwnam(u)))
	return MAVIS_DOWN;

    if (!pw->pw_dir) {
	av_set(*ac, AV_A_COMMENT, "home dir not set");
	av_set(*ac, AV_A_RESULT, AV_V_RESULT_FAIL);
	return MAVIS_FINAL;
    }

    uid = geteuid();
    seteuid(0);
    res = check_auth(mcx, u, p);
    seteuid(uid);

    /* The PAM routines may have spoiled our logging identity. */
    logopen();

    if (res) {
	char buf[1024];

	av_set(*ac, AV_A_DBPASSWORD, p);

	av_setf(*ac, AV_A_UID, "%lu", (u_long) pw->pw_uid);
	av_setf(*ac, AV_A_GID, "%lu", (u_long) pw->pw_gid);

	/* attempt to get supplemental groups */

	av_set(*ac, AV_A_GIDS, groups_getlist(pw->pw_name, pw->pw_gid, buf, sizeof(buf)));

	if (mcx->ftp_chroot) {
	    t = strstr(pw->pw_dir, "/./");
	    if (t) {
		*t = 0;
		av_set(*ac, AV_A_HOME, t + 2);
	    } else
		av_set(*ac, AV_A_HOME, "/");
	    av_set(*ac, AV_A_ROOT, pw->pw_dir);
	} else {
	    av_set(*ac, AV_A_HOME, pw->pw_dir);
	    av_set(*ac, AV_A_ROOT, "/");
	}
    } else
	av_set(*ac, AV_A_RESULT, AV_V_RESULT_FAIL);
    return MAVIS_FINAL;
}