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