1/*++
2/* NAME
3/*	token 3
4/* SUMMARY
5/*	tokenize alias/include/.forward entries and deliver
6/* SYNOPSIS
7/*	#include "local.h"
8/*
9/*	int	deliver_token(state, usr_attr, addr)
10/*	LOCAL_STATE state;
11/*	USER_ATTR usr_attr;
12/*	TOK822	*addr;
13/*
14/*	int	deliver_token_string(state, usr_attr, string, addr_count)
15/*	LOCAL_STATE state;
16/*	USER_ATTR usr_attr;
17/*	char	*string;
18/*	int	*addr_count;
19/*
20/*	int	deliver_token_stream(state, usr_attr, fp, addr_count)
21/*	LOCAL_STATE state;
22/*	USER_ATTR usr_attr;
23/*	VSTREAM	*fp;
24/*	int	*addr_count;
25/* DESCRIPTION
26/*	This module delivers to addresses listed in an alias database
27/*	entry, in an include file, or in a .forward file.
28/*
29/*	deliver_token() delivers to the address in the given token:
30/*	an absolute /path/name, a ~/path/name relative to the recipient's
31/*	home directory, an :include:/path/name request, an external
32/*	"|command", or a mail address.
33/*
34/*	deliver_token_string() delivers to all addresses listed in
35/*	the specified string.
36/*
37/*	deliver_token_stream() delivers to all addresses listed in
38/*	the specified stream. Input records > \fIline_length_limit\fR
39/*	are broken up into multiple records, to prevent the mail
40/*	system from using unreasonable amounts of memory.
41/*
42/*	Arguments:
43/* .IP state
44/*	The attributes that specify the message, recipient and more.
45/*	Attributes describing alias, include or forward expansion.
46/*	A table with the results from expanding aliases or lists.
47/*	A table with delivered-to: addresses taken from the message.
48/* .IP usr_attr
49/*	Attributes describing user rights and environment.
50/* .IP addr
51/*	A parsed address from an include file, alias file or .forward file.
52/* .IP string
53/*	A null-terminated string.
54/* .IP fp
55/*	A readable stream.
56/* .IP addr_count
57/*	Null pointer, or the address of a counter that is incremented
58/*	by the number of destinations found by the tokenizer.
59/* DIAGNOSTICS
60/*	Fatal errors: out of memory. The result is non-zero when the
61/*	operation should be tried again. Warnings: malformed address.
62/* SEE ALSO
63/*	list_token(3) tokenize list
64/* LICENSE
65/* .ad
66/* .fi
67/*	The Secure Mailer license must be distributed with this software.
68/* AUTHOR(S)
69/*	Wietse Venema
70/*	IBM T.J. Watson Research
71/*	P.O. Box 704
72/*	Yorktown Heights, NY 10598, USA
73/*--*/
74
75/* System library. */
76
77#include <sys_defs.h>
78#include <unistd.h>
79#include <string.h>
80
81#ifdef STRCASECMP_IN_STRINGS_H
82#include <strings.h>
83#endif
84
85/* Utility library. */
86
87#include <msg.h>
88#include <vstring.h>
89#include <vstream.h>
90#include <htable.h>
91#include <readlline.h>
92#include <mymalloc.h>
93#include <vstring_vstream.h>
94#include <stringops.h>
95
96/* Global library. */
97
98#include <tok822.h>
99#include <mail_params.h>
100#include <bounce.h>
101#include <defer.h>
102
103/* Application-specific. */
104
105#include "local.h"
106
107/* deliver_token_home - expand ~token */
108
109static int deliver_token_home(LOCAL_STATE state, USER_ATTR usr_attr, char *addr)
110{
111    char   *full_path;
112    int     status;
113
114    if (addr[1] != '/') {			/* disallow ~user */
115	msg_warn("bad home directory syntax for: %s", addr);
116	dsb_simple(state.msg_attr.why, "5.3.5",
117		   "mail system configuration error");
118	status = bounce_append(BOUNCE_FLAGS(state.request),
119			       BOUNCE_ATTR(state.msg_attr));
120    } else if (usr_attr.home == 0) {		/* require user context */
121	msg_warn("unknown home directory for: %s", addr);
122	dsb_simple(state.msg_attr.why, "5.3.5",
123		   "mail system configuration error");
124	status = bounce_append(BOUNCE_FLAGS(state.request),
125			       BOUNCE_ATTR(state.msg_attr));
126    } else if (usr_attr.home[0] == '/' && usr_attr.home[1] == 0) {
127	status = deliver_file(state, usr_attr, addr + 1);
128    } else {					/* expand ~ to home */
129	full_path = concatenate(usr_attr.home, addr + 1, (char *) 0);
130	status = deliver_file(state, usr_attr, full_path);
131	myfree(full_path);
132    }
133    return (status);
134}
135
136/* deliver_token - deliver to expansion of include file or alias */
137
138int     deliver_token(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr)
139{
140    VSTRING *addr_buf = vstring_alloc(100);
141    static char include[] = ":include:";
142    int     status;
143    char   *path;
144
145    tok822_internalize(addr_buf, addr->head, TOK822_STR_DEFL);
146    if (msg_verbose)
147	msg_info("deliver_token: %s", STR(addr_buf));
148
149    if (*STR(addr_buf) == '/') {
150	status = deliver_file(state, usr_attr, STR(addr_buf));
151    } else if (*STR(addr_buf) == '~') {
152	status = deliver_token_home(state, usr_attr, STR(addr_buf));
153    } else if (*STR(addr_buf) == '|') {
154	if ((local_cmd_deliver_mask & state.msg_attr.exp_type) == 0) {
155	    dsb_simple(state.msg_attr.why, "5.7.1",
156		       "mail to command is restricted");
157	    status = bounce_append(BOUNCE_FLAGS(state.request),
158				   BOUNCE_ATTR(state.msg_attr));
159	} else
160	    status = deliver_command(state, usr_attr, STR(addr_buf) + 1);
161    } else if (strncasecmp(STR(addr_buf), include, sizeof(include) - 1) == 0) {
162	path = STR(addr_buf) + sizeof(include) - 1;
163	status = deliver_include(state, usr_attr, path);
164    } else {
165	status = deliver_resolve_tree(state, usr_attr, addr);
166    }
167    vstring_free(addr_buf);
168
169    return (status);
170}
171
172/* deliver_token_string - tokenize string and deliver */
173
174int     deliver_token_string(LOCAL_STATE state, USER_ATTR usr_attr,
175			             char *string, int *addr_count)
176{
177    TOK822 *tree;
178    TOK822 *addr;
179    int     status = 0;
180
181    if (msg_verbose)
182	msg_info("deliver_token_string: %s", string);
183
184    tree = tok822_parse(string);
185    for (addr = tree; addr != 0; addr = addr->next) {
186	if (addr->type == TOK822_ADDR) {
187	    if (addr_count)
188		(*addr_count)++;
189	    status |= deliver_token(state, usr_attr, addr);
190	}
191    }
192    tok822_free_tree(tree);
193    return (status);
194}
195
196/* deliver_token_stream - tokenize stream and deliver */
197
198int     deliver_token_stream(LOCAL_STATE state, USER_ATTR usr_attr,
199			             VSTREAM *fp, int *addr_count)
200{
201    VSTRING *buf = vstring_alloc(100);
202    int     status = 0;
203
204    if (msg_verbose)
205	msg_info("deliver_token_stream: %s", VSTREAM_PATH(fp));
206
207    while (vstring_fgets_bound(buf, fp, var_line_limit)) {
208	if (*STR(buf) != '#') {
209	    status = deliver_token_string(state, usr_attr, STR(buf), addr_count);
210	    if (status != 0)
211		break;
212	}
213    }
214    if (vstream_ferror(fp)) {
215	dsb_simple(state.msg_attr.why, "4.3.0",
216		   "error reading forwarding file: %m");
217	status = defer_append(BOUNCE_FLAGS(state.request),
218			      BOUNCE_ATTR(state.msg_attr));
219    }
220    vstring_free(buf);
221    return (status);
222}
223