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