cleanup_map1n.c revision 1.4
1/*	$NetBSD: cleanup_map1n.c,v 1.4 2023/12/23 20:30:43 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/*	Wietse Venema
46/*	Google, Inc.
47/*	111 8th Avenue
48/*	New York, NY 10011, USA
49/*--*/
50
51/* System library. */
52
53#include <sys_defs.h>
54#include <string.h>
55
56/* Utility library. */
57
58#include <mymalloc.h>
59#include <msg.h>
60#include <argv.h>
61#include <vstring.h>
62#include <dict.h>
63#include <stringops.h>
64
65/* Global library. */
66
67#include <mail_params.h>
68#include <mail_addr_map.h>
69#include <cleanup_user.h>
70#include <quote_822_local.h>
71#include <been_here.h>
72
73/* Application-specific. */
74
75#include "cleanup.h"
76
77/* cleanup_map1n_internal - one-to-many table lookups */
78
79ARGV   *cleanup_map1n_internal(CLEANUP_STATE *state, const char *addr,
80			               MAPS *maps, int propagate)
81{
82    ARGV   *argv;
83    ARGV   *lookup;
84    int     count;
85    int     i;
86    int     arg;
87    BH_TABLE *been_here;
88    char   *saved_lhs;
89
90    /*
91     * Initialize.
92     */
93    argv = argv_alloc(1);
94    argv_add(argv, addr, ARGV_END);
95    argv_terminate(argv);
96    been_here = been_here_init(0, BH_FLAG_FOLD);
97
98    /*
99     * Rewrite the address vector in place. With each map lookup result,
100     * split it into separate addresses, then rewrite and flatten each
101     * address, and repeat the process. Beware: argv is being changed, so we
102     * must index the array explicitly, instead of running along it with a
103     * pointer.
104     */
105#define UPDATE(ptr,new)	do { \
106	if (ptr) { myfree(ptr); } ptr = mystrdup(new); \
107    } while (0)
108#define STR	vstring_str
109#define RETURN(x) do { \
110	been_here_free(been_here); return (x); \
111    } while (0)
112#define UNEXPAND(argv, addr) do { \
113	argv_truncate((argv), 0); argv_add((argv), (addr), (char *) 0); \
114    } while (0)
115
116    for (arg = 0; arg < argv->argc; arg++) {
117	if (argv->argc > var_virt_expan_limit) {
118	    msg_warn("%s: unreasonable %s map expansion size for %s -- "
119		     "message not accepted, try again later",
120		     state->queue_id, maps->title, addr);
121	    state->errs |= CLEANUP_STAT_DEFER;
122	    UPDATE(state->reason, "4.6.0 Alias expansion error");
123	    UNEXPAND(argv, addr);
124	    RETURN(argv);
125	}
126	for (count = 0; /* void */ ; count++) {
127
128	    /*
129	     * Don't expand an address that already expanded into itself.
130	     */
131	    if (been_here_check_fixed(been_here, argv->argv[arg]) != 0)
132		break;
133	    if (count >= var_virt_recur_limit) {
134		msg_warn("%s: unreasonable %s map nesting for %s -- "
135			 "message not accepted, try again later",
136			 state->queue_id, maps->title, addr);
137		state->errs |= CLEANUP_STAT_DEFER;
138		UPDATE(state->reason, "4.6.0 Alias expansion error");
139		UNEXPAND(argv, addr);
140		RETURN(argv);
141	    }
142	    if ((lookup = mail_addr_map_internal(maps, argv->argv[arg],
143						 propagate)) != 0) {
144		saved_lhs = mystrdup(argv->argv[arg]);
145		for (i = 0; i < lookup->argc; i++) {
146		    if (strlen(lookup->argv[i]) > var_virt_addrlen_limit) {
147			msg_warn("%s: unreasonable %s result %.300s... -- "
148				 "message not accepted, try again later",
149			     state->queue_id, maps->title, lookup->argv[i]);
150			state->errs |= CLEANUP_STAT_DEFER;
151			UPDATE(state->reason, "4.6.0 Alias expansion error");
152			UNEXPAND(argv, addr);
153			RETURN(argv);
154		    }
155		    if (i == 0) {
156			UPDATE(argv->argv[arg], lookup->argv[i]);
157		    } else {
158			argv_add(argv, lookup->argv[i], ARGV_END);
159			argv_terminate(argv);
160		    }
161
162		    /*
163		     * Allow an address to expand into itself once.
164		     */
165		    if (strcasecmp_utf8(saved_lhs, lookup->argv[i]) == 0)
166			been_here_fixed(been_here, saved_lhs);
167		}
168		myfree(saved_lhs);
169		argv_free(lookup);
170	    } else if (maps->error != 0) {
171		msg_warn("%s: %s map lookup problem for %s -- "
172			 "message not accepted, try again later",
173			 state->queue_id, maps->title, addr);
174		state->errs |= CLEANUP_STAT_WRITE;
175		UPDATE(state->reason, "4.6.0 Alias expansion error");
176		UNEXPAND(argv, addr);
177		RETURN(argv);
178	    } else {
179		break;
180	    }
181	}
182    }
183    RETURN(argv);
184}
185