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