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;
}
|