File: resolve.c

package info (click to toggle)
smail 3.2.0.102-1
  • links: PTS
  • area: main
  • in suites: slink
  • size: 4,228 kB
  • ctags: 3,924
  • sloc: ansic: 41,366; sh: 3,434; makefile: 2,349; awk: 689; perl: 598; yacc: 427; sed: 2
file content (249 lines) | stat: -rw-r--r-- 8,005 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
/*
#ident	"@(#)smail/src:RELEASE-3_2_0_102:resolve.c,v 1.13 1998/08/02 17:41:35 woods Exp"
 */

/*
 *    Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
 *    Copyright (C) 1992  Ronald S. Karr
 * 
 * See the file COPYING, distributed with smail, for restriction
 * and warranty information.
 */

/*
 * resolve.c:
 *	resolve addresses to completed addr structures with transports.
 *
 *	external functions: resolve_addr_list, islocalhost
 */
#include <sys/types.h>
#include <stdio.h>
#include "defs.h"
#include "smail.h"
#include "dys.h"
#include "hash.h"
#include "log.h"
#include "addr.h"
#include "route.h"
#include "transport.h"
#include "exitcodes.h"
#ifndef DEPEND
# include "extern.h"
# include "debug.h"
# include "error.h"
#endif

/* exported variables */
struct hash_table *hit_table;		/* table to recognize address hits */


/*
 * resolve_addr_list - resolve addresses to transports and next hosts
 *
 * given a list of user-supplied addresses on input, produce resolved
 * and unresolvable addresses on output.
 *
 * inputs:
 *	in	- the list of input address structures
 *
 * outputs:
 *	out	- the list of completely resolved address structures.
 *		  transport, next_host and next_addr will be properly
 *		  filled in for all of these structures.
 *	defer	- a list of temporarily unresolvable address structures.
 *		  an error structure is stored in the error element.
 *		  These addresses should be retried at a later time.  If
 *		  ERR_CONFERR is set in the error->info element, the
 *		  problem is a configuration error.
 *	fail	- a list of unresolvable address structures.  An error
 *		  structure is stored in the error element.  If
 *		  ERR_NSENDER is set, a note is returned to the sender.
 *		  If ERR_NPOSTMASTER is set, then a note is mailed to
 *		  the postmaster.  If ERR_NSOWNER is set then a note is
 *		  sent to an owner for an address, or to the sender if
 *		  the address has no owner.  If ERR_NPOWNER is set then
 *		  a note is sent to an owner or to the postmaster if the
 *		  address has no owner.
 */
void
resolve_addr_list(in, out, defer, fail, hash_addrs)
    struct addr *in;			/* the address list to resolve */
    struct addr **out;			/* produced addr list w/transports */
    struct addr **defer;		/* addrs to defer to a later time */
    struct addr **fail;			/* unresolvable addrs */
    int hash_addrs;			/* TRUE to prevent duplicate addrs */
{
    struct addr *cur;			/* current address being processed */
    struct addr *local;			/* addrs that parsed local */
    struct addr *remote;		/* addrs that parsed remote */
    struct addr *next;			/* next value for cur */

    remote = NULL;
    local = NULL;

    DEBUG(DBG_RESOLVE_HI, "resolve_addr_list called\n");

    /*
     * Resolve all addresses in our input queue.
     *
     * Each step through the loop advances the progress
     * in resolving all addresses to a transport.
     *
     * The loop is done when nothing remains to be processed.
     *
     * As an optimization, remote form processing is not
     * done unless/until no local processing was required.
     */
    while (in || remote) {
	/*
	 * split the input list into local and remote forms.
	 */
	for (cur = in, in = NULL; cur; cur = next) {
	    int form;			/* address form from parse_address() */

	    DEBUG1(DBG_RESOLVE_HI, "resolve_addr_list working on %s.\n", cur->work_addr);
	    next = cur->succ;

	    /* First, if allowed, we try adding the current address to the
	     * master hash table to ensure we don't do extra work checking
	     * obviously identical addresses.  Note that since we don't
	     * re-parse anything that looks anything like a remote address we
	     * don't protect from multiple deliveries to different addresses
	     * that really do resolve to the same adress.  We leave final
	     * duplicate stripping to a final scan of the out list.
	     */
	    if (hash_addrs &&
		!(cur->flags & ADDR_DONTHASH) &&
		add_to_hash(cur->work_addr, (char *)NULL, 0, hit_table) == ALREADY_HASHED) {
		DEBUG1(DBG_RESOLVE_LO, "%s: has already been seen -- skipping.\n", cur->work_addr);
		continue;
	    }

	    form = parse_address(cur->work_addr, &cur->target,
				 &cur->remainder, &cur->parseflags);
	    switch (form) {
	    case FAIL:
	    case PARSE_ERROR:
		/*
		 * ERR_111 - address parse error
		 *
		 * DESCRIPTION
		 *      parse_address() encountered an error while parsing
		 *      the work_addr for this address.  The error is stored
		 *      in cur->remainder.
		 *
		 * ACTIONS
		 *      A message about the parse error should be returned
		 *      to the owner of the address or to the sender.
		 *
		 * RESOLUTION
		 *      The owner or sender should correct the address and
		 *      resubmit the message.
		 */
		cur->error = note_error(ERR_NSOWNER|ERR_111, cur->remainder);
		cur->flags |= PARSE_ERROR;
		cur->succ = *fail;
		*fail = cur;
		continue;

	    case LOCAL:
		/*
		 * a local-form in quotes must be reparsed
		 */
		if (strip(cur->remainder)) {
		    /* it was in quotes, put it back on the input */
		    DEBUG1(DBG_RESOLVE_HI, "re-parsing quoted local form %s.\n", cur->remainder);
		    next = cur;
		} else {
		    if (!cur->local_name)
			cur->local_name = visible_name;
		    cur->succ = local;
		    local = cur;
		    DEBUG1(DBG_RESOLVE_HI, "moved local form %s to be directed.\n", cur->remainder);
		}
		break;

	    default:			/* anything else is a remote-form address */
		/* determine if the target host is actually a local host */
		if (islocalhost(cur->target)) {
		    DEBUG1(DBG_RESOLVE_HI, "target %s was actually a local host, will reparse remainder.\n", cur->target);
		    /* remember the local name */
		    cur->local_name = COPY_STRING(cur->target);/* XXX will leak? */
		    /* it is a local host, but save the name for virtual host processing */
		    cur->work_addr = COPY_STRING(cur->remainder);/* XXX will leak? */
		    next = cur;		/* erni: must parse again, remainder could be remote */
		    continue;
		}
		cur->flags &= ~(ADDR_FORM_MASK);
		cur->flags |= form;
		cur->succ = remote;
		remote = cur;
		DEBUG1(DBG_RESOLVE_HI, "moved target %s to be routed.\n", cur->target);
		break;
	    }
	}

	/*
	 * either process local or remote addresses.
	 */
	if (local) {
	    direct_local_addrs(local, out, &in, defer, fail);
	    local = NULL;
	} else {
	    route_remote_addrs(remote, out, &in, defer, fail);
	    remote = NULL;
	}
    }
    /* XXX we could probably garbage-collect hit_table at this point */
    if (hash_addrs) {
	struct addr *prev;
	struct hash_table *hit_out_table; /* table to recognize address hits */
	char *hashval;

	/* XXX - hit_out_table should be associated with a block */
	hit_out_table = new_hash_table(hit_table_len,
				       (struct block *) NULL,
				       HASH_DEFAULT);
	/*
	 * Re-scan the out list for duplicates.  Note that a duplicate is
	 * one that has the same destination *and* the same transport.
	 */
	for (cur = *out, prev = NULL; cur; cur = next) {
	    next = cur->succ;
	    hashval = xprintf("%s at %s via %s",
			      cur->next_addr,
			      cur->next_host ? cur->next_host : "(localhost)",
			      cur->transport->name);
	    if (add_to_hash(hashval, (char *) NULL, 0, hit_out_table) == ALREADY_HASHED) {
		DEBUG1(DBG_RESOLVE_LO, "%s: has already been seen -- skipping.\n", hashval);
		prev->succ = next;
		cur->succ = NULL;
		/* XXX should probably garbage collect the duplicate */
	    } else {
		prev = cur;
	    }
	    xfree(hashval);
	}
    }
}

/*
 * islocalhost - determine if the given target is the local host
 *
 * given the currently known names for the localhost, determine
 * if the given name matches one of these known names.
 *
 * return TRUE or FALSE.
 */
int
islocalhost(target)
    register char *target;		/* name to match */
{
    if ((uucp_name && EQIC(target, uucp_name)) ||
	(hostnames && is_string_in_list(target, hostnames)) ||
	(more_hostnames && is_string_in_list(target, more_hostnames)))
    {
	return TRUE;
    }
    return FALSE;
}