예제 #1
0
static void
lka_expand(struct lka_session *lks, struct rule *rule, struct expandnode *xn)
{
	struct forward_req	fwreq;
	struct envelope		ep;
	struct expandnode	node;
	struct mailaddr		maddr;
	int			r;
	union lookup		lk;

	if (xn->depth >= EXPAND_DEPTH) {
		log_trace(TRACE_EXPAND, "expand: lka_expand: node too deep.");
		lks->error = LKA_PERMFAIL;
		return;
	}

	switch (xn->type) {
	case EXPAND_INVALID:
	case EXPAND_INCLUDE:
		fatalx("lka_expand: unexpected type");
		break;

	case EXPAND_ADDRESS:

		log_trace(TRACE_EXPAND, "expand: lka_expand: address: %s@%s "
		    "[depth=%d]",
		    xn->u.mailaddr.user, xn->u.mailaddr.domain, xn->depth);

		/* Pass the node through the ruleset */
		ep = lks->envelope;
		ep.dest = xn->u.mailaddr;
		if (xn->parent) /* nodes with parent are forward addresses */
			ep.flags |= EF_INTERNAL;
		rule = ruleset_match(&ep);
		if (rule == NULL || rule->r_decision == R_REJECT) {
			lks->error = (errno == EAGAIN) ?
			    LKA_TEMPFAIL : LKA_PERMFAIL;
			break;
		}

		xn->mapping = rule->r_mapping;
		xn->userbase = rule->r_userbase;

		if (rule->r_action == A_RELAY || rule->r_action == A_RELAYVIA) {
			lka_submit(lks, rule, xn);
		}
		else if (rule->r_desttype == DEST_VDOM) {
			/* expand */
			lks->expand.rule = rule;
			lks->expand.parent = xn;
			lks->expand.alias = 1;

			/* temporary replace the mailaddr with a copy where
			 * we eventually strip the '+'-part before lookup.
			 */
			maddr = xn->u.mailaddr;
			mailaddr_to_username(&xn->u.mailaddr, maddr.user,
			    sizeof maddr.user);

			r = aliases_virtual_get(&lks->expand, &maddr);
			if (r == -1) {
				lks->error = LKA_TEMPFAIL;
				log_trace(TRACE_EXPAND, "expand: lka_expand: "
				    "error in virtual alias lookup");
			}
			else if (r == 0) {
				lks->error = LKA_PERMFAIL;
				log_trace(TRACE_EXPAND, "expand: lka_expand: "
				    "no aliases for virtual");
			}
		}
		else {
			lks->expand.rule = rule;
			lks->expand.parent = xn;
			lks->expand.alias = 1;
			bzero(&node, sizeof node);
			node.type = EXPAND_USERNAME;
			mailaddr_to_username(&xn->u.mailaddr, node.u.user,
				sizeof node.u.user);
			node.mapping = rule->r_mapping;
			node.userbase = rule->r_userbase;
			expand_insert(&lks->expand, &node);
		}
		break;

	case EXPAND_USERNAME:
		log_trace(TRACE_EXPAND, "expand: lka_expand: username: %s "
		    "[depth=%d]", xn->u.user, xn->depth);

		if (xn->sameuser) {
			log_trace(TRACE_EXPAND, "expand: lka_expand: same "
			    "user, submitting");
			lka_submit(lks, rule, xn);
			break;
		}

		/* expand aliases with the given rule */
		lks->expand.rule = rule;
		lks->expand.parent = xn;
		lks->expand.alias = 1;
		xn->mapping = rule->r_mapping;
		xn->userbase = rule->r_userbase;
		if (rule->r_mapping) {
			r = aliases_get(&lks->expand, xn->u.user);
			if (r == -1) {
				log_trace(TRACE_EXPAND, "expand: lka_expand: "
				    "error in alias lookup");
				lks->error = LKA_TEMPFAIL;
			}
			if (r)
				break;
		}

		/* A username should not exceed the size of a system user */
		if (strlen(xn->u.user) >= sizeof fwreq.user) {
			log_trace(TRACE_EXPAND, "expand: lka_expand: "
			    "user-part too long to be a system user");
			lks->error = LKA_PERMFAIL;
			break;
		}

		r = table_lookup(rule->r_userbase, xn->u.user, K_USERINFO, &lk);
		if (r == -1) {
			log_trace(TRACE_EXPAND, "expand: lka_expand: "
			    "backend error while searching user");
			lks->error = LKA_TEMPFAIL;
			break;
		}
		if (r == 0) {
			log_trace(TRACE_EXPAND, "expand: lka_expand: "
			    "user-part does not match system user");
			lks->error = LKA_PERMFAIL;
			break;
		}

		/* no aliases found, query forward file */
		lks->rule = rule;
		lks->node = xn;
		fwreq.id = lks->id;
		(void)strlcpy(fwreq.user, lk.userinfo.username, sizeof(fwreq.user));
		(void)strlcpy(fwreq.directory, lk.userinfo.directory, sizeof(fwreq.directory));
		fwreq.uid = lk.userinfo.uid;
		fwreq.gid = lk.userinfo.gid;
		m_compose(p_parent, IMSG_PARENT_FORWARD_OPEN, 0, 0, -1,
		    &fwreq, sizeof(fwreq));
		lks->flags |= F_WAITING;
		break;

	case EXPAND_FILENAME:
		log_trace(TRACE_EXPAND, "expand: lka_expand: filename: %s "
		    "[depth=%d]", xn->u.buffer, xn->depth);
		lka_submit(lks, rule, xn);
		break;

	case EXPAND_ERROR:
		log_trace(TRACE_EXPAND, "expand: lka_expand: error: %s "
		    "[depth=%d]", xn->u.buffer, xn->depth);
		if (xn->u.buffer[0] == '4')
			lks->error = LKA_TEMPFAIL;
		else if (xn->u.buffer[0] == '5')
			lks->error = LKA_PERMFAIL;
		lks->errormsg = xn->u.buffer;
		break;

	case EXPAND_FILTER:
		log_trace(TRACE_EXPAND, "expand: lka_expand: filter: %s "
		    "[depth=%d]", xn->u.buffer, xn->depth);
		lka_submit(lks, rule, xn);
		break;
	}
}
예제 #2
0
파일: lka.c 프로젝트: toddfries/OpenSMTPD
static void
lka_imsg(struct imsgev *iev, struct imsg *imsg)
{
    struct submit_status	*ss;
    struct secret		*secret;
    struct mapel		*mapel;
    struct rule		*rule;
    struct map		*map;
    struct map		*mp;
    void			*tmp;

    if (imsg->hdr.type == IMSG_DNS_HOST || imsg->hdr.type == IMSG_DNS_MX ||
            imsg->hdr.type == IMSG_DNS_PTR) {
        dns_async(iev, imsg->hdr.type, imsg->data);
        return;
    }

    if (iev->proc == PROC_MFA) {
        switch (imsg->hdr.type) {
        case IMSG_LKA_MAIL:
            ss = imsg->data;
            ss->code = 530;
            if (ss->u.maddr.user[0] == '\0' &&
                    ss->u.maddr.domain[0] == '\0')
                ss->code = 250;
            else if (lka_verify_mail(&ss->u.maddr))
                ss->code = 250;
            imsg_compose_event(iev, IMSG_LKA_MAIL, 0, 0, -1, ss,
                               sizeof *ss);
            return;

        case IMSG_LKA_RULEMATCH:
            ss = imsg->data;
            rule = ruleset_match(&ss->envelope);
            if (rule == NULL)
                ss->code = (errno == EAGAIN) ? 451 : 530;
            else
                ss->code = (rule->r_decision == R_ACCEPT) ?
                           250 : 530;
            imsg_compose_event(iev, IMSG_LKA_RULEMATCH, 0, 0, -1,
                               ss, sizeof *ss);
            return;

        case IMSG_LKA_RCPT:
            lka_session(imsg->data);
            return;
        }
    }

    if (iev->proc == PROC_MTA) {
        switch (imsg->hdr.type) {
        case IMSG_LKA_SECRET: {
            struct map_credentials *map_credentials;

            secret = imsg->data;
            map = map_findbyname(secret->mapname);
            if (map == NULL) {
                log_warn("warn: lka: credentials map %s is missing",
                         secret->mapname);
                imsg_compose_event(iev, IMSG_LKA_SECRET, 0, 0,
                                   -1, secret, sizeof *secret);
                return;
            }
            map_credentials = map_lookup(map->m_id, secret->host,
                                         K_CREDENTIALS);
            log_debug("debug: lka: %s credentials lookup (%d)", secret->host,
                      map_credentials != NULL);
            secret->secret[0] = '\0';
            if (map_credentials == NULL)
                log_warnx("warn: %s credentials not found",
                          secret->host);
            else if (lka_encode_credentials(secret->secret,
                                            sizeof secret->secret, map_credentials) == 0)
                log_warnx("warn: %s credentials parse fail",
                          secret->host);
            imsg_compose_event(iev, IMSG_LKA_SECRET, 0, 0, -1, secret,
                               sizeof *secret);
            free(map_credentials);
            return;
        }
        }
    }

    if (iev->proc == PROC_PARENT) {
        switch (imsg->hdr.type) {
        case IMSG_CONF_START:
            env->sc_rules_reload = xcalloc(1, sizeof *env->sc_rules,
                                           "lka:sc_rules_reload");
            env->sc_maps_reload = xcalloc(1, sizeof *env->sc_maps,
                                          "lka:sc_maps_reload");
            TAILQ_INIT(env->sc_rules_reload);
            TAILQ_INIT(env->sc_maps_reload);
            return;

        case IMSG_CONF_RULE:
            rule = xmemdup(imsg->data, sizeof *rule, "lka:rule");
            TAILQ_INSERT_TAIL(env->sc_rules_reload, rule, r_entry);
            return;

        case IMSG_CONF_MAP:
            map = xmemdup(imsg->data, sizeof *map, "lka:map");
            TAILQ_INIT(&map->m_contents);
            TAILQ_INSERT_TAIL(env->sc_maps_reload, map, m_entry);

            tmp = env->sc_maps;
            env->sc_maps = env->sc_maps_reload;

            mp = map_open(map);
            if (mp == NULL)
                errx(1, "lka: could not open map \"%s\"", map->m_name);
            map_close(map, mp);

            env->sc_maps = tmp;
            return;

        case IMSG_CONF_RULE_SOURCE:
            rule = TAILQ_LAST(env->sc_rules_reload, rulelist);
            tmp = env->sc_maps;
            env->sc_maps = env->sc_maps_reload;
            rule->r_sources = map_findbyname(imsg->data);
            if (rule->r_sources == NULL)
                fatalx("lka: maps inconsistency");
            env->sc_maps = tmp;
            return;

        case IMSG_CONF_MAP_CONTENT:
            map = TAILQ_LAST(env->sc_maps_reload, maplist);
            mapel = xmemdup(imsg->data, sizeof *mapel, "lka:mapel");
            TAILQ_INSERT_TAIL(&map->m_contents, mapel, me_entry);
            return;

        case IMSG_CONF_END:
            if (env->sc_rules)
                purge_config(PURGE_RULES);
            if (env->sc_maps)
                purge_config(PURGE_MAPS);
            env->sc_rules = env->sc_rules_reload;
            env->sc_maps = env->sc_maps_reload;

            /* start fulfilling requests */
            event_add(&env->sc_ievs[PROC_MTA]->ev, NULL);
            event_add(&env->sc_ievs[PROC_MFA]->ev, NULL);
            event_add(&env->sc_ievs[PROC_SMTP]->ev, NULL);
            return;

        case IMSG_CTL_VERBOSE:
            log_verbose(*(int *)imsg->data);
            return;

        case IMSG_PARENT_FORWARD_OPEN:
            lka_session_forward_reply(imsg->data, imsg->fd);
            return;

        }
    }

    if (iev->proc == PROC_CONTROL) {
        switch (imsg->hdr.type) {
        case IMSG_LKA_UPDATE_MAP:
            map = map_findbyname(imsg->data);
            if (map == NULL) {
                log_warnx("warn: lka: no such map \"%s\"",
                          (char *)imsg->data);
                return;
            }
            map_update(map);
            return;
        }
    }

    errx(1, "lka_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
}