1 /*	$NetBSD: cleanup_map1n.c,v 1.1.1.1 2009/06/23 10:08:43 tron 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, or when a maximal
21 /*	nesting level is reached.
22 /*
23 /*	cleanup_map1n_internal() is the interface for addresses in
24 /*	internal (unquoted) form.
25 /* DIAGNOSTICS
26 /*	Recoverable errors: the global \fIcleanup_errs\fR flag is updated.
27 /* SEE ALSO
28 /*	mail_addr_map(3) address mappings
29 /*	mail_addr_find(3) address lookups
30 /* LICENSE
31 /* .ad
32 /* .fi
33 /*	The Secure Mailer license must be distributed with this software.
34 /* AUTHOR(S)
35 /*	Wietse Venema
36 /*	IBM T.J. Watson Research
37 /*	P.O. Box 704
38 /*	Yorktown Heights, NY 10598, USA
39 /*--*/
40 
41 /* System library. */
42 
43 #include <sys_defs.h>
44 #include <string.h>
45 
46 #ifdef STRCASECMP_IN_STRINGS_H
47 #include <strings.h>
48 #endif
49 
50 /* Utility library. */
51 
52 #include <mymalloc.h>
53 #include <msg.h>
54 #include <argv.h>
55 #include <vstring.h>
56 #include <dict.h>
57 
58 /* Global library. */
59 
60 #include <mail_params.h>
61 #include <mail_addr_map.h>
62 #include <cleanup_user.h>
63 #include <quote_822_local.h>
64 #include <been_here.h>
65 
66 /* Application-specific. */
67 
68 #include "cleanup.h"
69 
70 /* cleanup_map1n_internal - one-to-many table lookups */
71 
72 ARGV   *cleanup_map1n_internal(CLEANUP_STATE *state, const char *addr,
73 			               MAPS *maps, int propagate)
74 {
75     ARGV   *argv;
76     ARGV   *lookup;
77     int     count;
78     int     i;
79     int     arg;
80     BH_TABLE *been_here;
81     char   *saved_lhs;
82 
83     /*
84      * Initialize.
85      */
86     argv = argv_alloc(1);
87     argv_add(argv, addr, ARGV_END);
88     argv_terminate(argv);
89     been_here = been_here_init(0, BH_FLAG_FOLD);
90 
91     /*
92      * Rewrite the address vector in place. With each map lookup result,
93      * split it into separate addresses, then rewrite and flatten each
94      * address, and repeat the process. Beware: argv is being changed, so we
95      * must index the array explicitly, instead of running along it with a
96      * pointer.
97      */
98 #define UPDATE(ptr,new)	{ myfree(ptr); ptr = mystrdup(new); }
99 #define STR	vstring_str
100 #define RETURN(x) { been_here_free(been_here); return (x); }
101 
102     for (arg = 0; arg < argv->argc; arg++) {
103 	if (argv->argc > var_virt_expan_limit) {
104 	    msg_warn("%s: unreasonable %s map expansion size for %s",
105 		     state->queue_id, maps->title, addr);
106 	    break;
107 	}
108 	for (count = 0; /* void */ ; count++) {
109 
110 	    /*
111 	     * Don't expand an address that already expanded into itself.
112 	     */
113 	    if (been_here_check_fixed(been_here, argv->argv[arg]) != 0)
114 		break;
115 	    if (count >= var_virt_recur_limit) {
116 		msg_warn("%s: unreasonable %s map nesting for %s",
117 			 state->queue_id, maps->title, addr);
118 		break;
119 	    }
120 	    quote_822_local(state->temp1, argv->argv[arg]);
121 	    if ((lookup = mail_addr_map(maps, STR(state->temp1), propagate)) != 0) {
122 		saved_lhs = mystrdup(argv->argv[arg]);
123 		for (i = 0; i < lookup->argc; i++) {
124 		    unquote_822_local(state->temp1, lookup->argv[i]);
125 		    if (i == 0) {
126 			UPDATE(argv->argv[arg], STR(state->temp1));
127 		    } else {
128 			argv_add(argv, STR(state->temp1), ARGV_END);
129 			argv_terminate(argv);
130 		    }
131 
132 		    /*
133 		     * Allow an address to expand into itself once.
134 		     */
135 		    if (strcasecmp(saved_lhs, STR(state->temp1)) == 0)
136 			been_here_fixed(been_here, saved_lhs);
137 		}
138 		myfree(saved_lhs);
139 		argv_free(lookup);
140 	    } else if (dict_errno != 0) {
141 		msg_warn("%s: %s map lookup problem for %s",
142 			 state->queue_id, maps->title, addr);
143 		state->errs |= CLEANUP_STAT_WRITE;
144 		RETURN(argv);
145 	    } else {
146 		break;
147 	    }
148 	}
149     }
150     RETURN(argv);
151 }
152