xref: /netbsd-src/external/ibm-public/postfix/dist/src/cleanup/cleanup_map1n.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
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 
74 ARGV   *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