cleanup_map1n.c revision 1.2
1/*	$NetBSD: cleanup_map1n.c,v 1.2 2017/02/14 01:16:44 christos Exp $	*/
2
3/*++
4/* NAME
5/*	cleanup_map1n 3
6/* SUMMARY
7/*	one-to-many address mapping
8/* SYNOPSIS
9/*	#include <cleanup.h>
10/*
11/*	ARGV	*cleanup_map1n_internal(state, addr, maps, propagate)
12/*	CLEANUP_STATE *state;
13/*	const char *addr;
14/*	MAPS	*maps;
15/*	int	propagate;
16/* DESCRIPTION
17/*	This module implements one-to-many table mapping via table lookup.
18/*	Table lookups are done with quoted (externalized) address forms.
19/*	The process is recursive. The recursion terminates when the
20/*	left-hand side appears in its own expansion.
21/*
22/*	cleanup_map1n_internal() is the interface for addresses in
23/*	internal (unquoted) form.
24/* DIAGNOSTICS
25/*	When the maximal expansion or recursion limit is reached,
26/*	the alias is not expanded and the CLEANUP_STAT_DEFER error
27/*	is raised with reason "4.6.0 Alias expansion error".
28/*
29/*	When table lookup fails, the alias is not expanded and the
30/*	CLEANUP_STAT_WRITE error is raised with reason "4.6.0 Alias
31/*	expansion error".
32/* SEE ALSO
33/*	mail_addr_map(3) address mappings
34/*	mail_addr_find(3) address lookups
35/* LICENSE
36/* .ad
37/* .fi
38/*	The Secure Mailer license must be distributed with this software.
39/* AUTHOR(S)
40/*	Wietse Venema
41/*	IBM T.J. Watson Research
42/*	P.O. Box 704
43/*	Yorktown Heights, NY 10598, USA
44/*--*/
45
46/* System library. */
47
48#include <sys_defs.h>
49#include <string.h>
50
51/* Utility library. */
52
53#include <mymalloc.h>
54#include <msg.h>
55#include <argv.h>
56#include <vstring.h>
57#include <dict.h>
58#include <stringops.h>
59
60/* Global library. */
61
62#include <mail_params.h>
63#include <mail_addr_map.h>
64#include <cleanup_user.h>
65#include <quote_822_local.h>
66#include <been_here.h>
67
68/* Application-specific. */
69
70#include "cleanup.h"
71
72/* cleanup_map1n_internal - one-to-many table lookups */
73
74ARGV   *cleanup_map1n_internal(CLEANUP_STATE *state, const char *addr,
75			               MAPS *maps, int propagate)
76{
77    ARGV   *argv;
78    ARGV   *lookup;
79    int     count;
80    int     i;
81    int     arg;
82    BH_TABLE *been_here;
83    char   *saved_lhs;
84
85    /*
86     * Initialize.
87     */
88    argv = argv_alloc(1);
89    argv_add(argv, addr, ARGV_END);
90    argv_terminate(argv);
91    been_here = been_here_init(0, BH_FLAG_FOLD);
92
93    /*
94     * Rewrite the address vector in place. With each map lookup result,
95     * split it into separate addresses, then rewrite and flatten each
96     * address, and repeat the process. Beware: argv is being changed, so we
97     * must index the array explicitly, instead of running along it with a
98     * pointer.
99     */
100#define UPDATE(ptr,new)	do { \
101	if (ptr) myfree(ptr); ptr = mystrdup(new); \
102    } while (0)
103#define STR	vstring_str
104#define RETURN(x) do { \
105	been_here_free(been_here); return (x); \
106    } while (0)
107#define UNEXPAND(argv, addr) do { \
108	argv_truncate((argv), 0); argv_add((argv), (addr), (char *) 0); \
109    } while (0)
110
111    for (arg = 0; arg < argv->argc; arg++) {
112	if (argv->argc > var_virt_expan_limit) {
113	    msg_warn("%s: unreasonable %s map expansion size for %s -- "
114		     "message not accepted, try again later",
115		     state->queue_id, maps->title, addr);
116	    state->errs |= CLEANUP_STAT_DEFER;
117	    UPDATE(state->reason, "4.6.0 Alias expansion error");
118	    UNEXPAND(argv, addr);
119	    RETURN(argv);
120	}
121	for (count = 0; /* void */ ; count++) {
122
123	    /*
124	     * Don't expand an address that already expanded into itself.
125	     */
126	    if (been_here_check_fixed(been_here, argv->argv[arg]) != 0)
127		break;
128	    if (count >= var_virt_recur_limit) {
129		msg_warn("%s: unreasonable %s map nesting for %s -- "
130			 "message not accepted, try again later",
131			 state->queue_id, maps->title, addr);
132		state->errs |= CLEANUP_STAT_DEFER;
133		UPDATE(state->reason, "4.6.0 Alias expansion error");
134		UNEXPAND(argv, addr);
135		RETURN(argv);
136	    }
137	    quote_822_local(state->temp1, argv->argv[arg]);
138	    if ((lookup = mail_addr_map(maps, STR(state->temp1), propagate)) != 0) {
139		saved_lhs = mystrdup(argv->argv[arg]);
140		for (i = 0; i < lookup->argc; i++) {
141		    if (strlen(lookup->argv[i]) > var_virt_addrlen_limit) {
142			msg_warn("%s: unreasonable %s result %.300s... -- "
143				 "message not accepted, try again later",
144			     state->queue_id, maps->title, lookup->argv[i]);
145			state->errs |= CLEANUP_STAT_DEFER;
146			UPDATE(state->reason, "4.6.0 Alias expansion error");
147			UNEXPAND(argv, addr);
148			RETURN(argv);
149		    }
150		    unquote_822_local(state->temp1, lookup->argv[i]);
151		    if (i == 0) {
152			UPDATE(argv->argv[arg], STR(state->temp1));
153		    } else {
154			argv_add(argv, STR(state->temp1), ARGV_END);
155			argv_terminate(argv);
156		    }
157
158		    /*
159		     * Allow an address to expand into itself once.
160		     */
161		    if (strcasecmp_utf8(saved_lhs, STR(state->temp1)) == 0)
162			been_here_fixed(been_here, saved_lhs);
163		}
164		myfree(saved_lhs);
165		argv_free(lookup);
166	    } else if (maps->error != 0) {
167		msg_warn("%s: %s map lookup problem for %s -- "
168			 "message not accepted, try again later",
169			 state->queue_id, maps->title, addr);
170		state->errs |= CLEANUP_STAT_WRITE;
171		UPDATE(state->reason, "4.6.0 Alias expansion error");
172		UNEXPAND(argv, addr);
173		RETURN(argv);
174	    } else {
175		break;
176	    }
177	}
178    }
179    RETURN(argv);
180}
181