Postfix3.3.1
smtp_session.c
[詳解]
1 /*++
2 /* NAME
3 /* smtp_session 3
4 /* SUMMARY
5 /* SMTP_SESSION structure management
6 /* SYNOPSIS
7 /* #include "smtp.h"
8 /*
9 /* SMTP_SESSION *smtp_session_alloc(stream, iter, start, flags)
10 /* VSTREAM *stream;
11 /* SMTP_ITERATOR *iter;
12 /* time_t start;
13 /* int flags;
14 /*
15 /* void smtp_session_free(session)
16 /* SMTP_SESSION *session;
17 /*
18 /* int smtp_session_passivate(session, dest_prop, endp_prop)
19 /* SMTP_SESSION *session;
20 /* VSTRING *dest_prop;
21 /* VSTRING *endp_prop;
22 /*
23 /* SMTP_SESSION *smtp_session_activate(fd, iter, dest_prop, endp_prop)
24 /* int fd;
25 /* SMTP_ITERATOR *iter;
26 /* VSTRING *dest_prop;
27 /* VSTRING *endp_prop;
28 /* DESCRIPTION
29 /* smtp_session_alloc() allocates memory for an SMTP_SESSION structure
30 /* and initializes it with the given stream and destination, host name
31 /* and address information. The host name and address strings are
32 /* copied. The port is in network byte order.
33 /*
34 /* smtp_session_free() destroys an SMTP_SESSION structure and its
35 /* members, making memory available for reuse. It will handle the
36 /* case of a null stream and will assume it was given a different
37 /* purpose.
38 /*
39 /* smtp_session_passivate() flattens an SMTP session so that
40 /* it can be cached. The SMTP_SESSION structure is destroyed.
41 /*
42 /* smtp_session_activate() inflates a flattened SMTP session
43 /* so that it can be used. The input property arguments are
44 /* modified.
45 /*
46 /* Arguments:
47 /* .IP stream
48 /* A full-duplex stream.
49 /* .IP iter
50 /* The literal next-hop or fall-back destination including
51 /* the optional [] and including the :port or :service;
52 /* the name of the remote host;
53 /* the printable address of the remote host;
54 /* the remote port in network byte order.
55 /* .IP start
56 /* The time when this connection was opened.
57 /* .IP flags
58 /* Zero or more of the following:
59 /* .RS
60 /* .IP SMTP_MISC_FLAG_CONN_LOAD
61 /* Enable re-use of cached SMTP or LMTP connections.
62 /* .IP SMTP_MISC_FLAG_CONN_STORE
63 /* Enable saving of cached SMTP or LMTP connections.
64 /* .RE
65 /* SMTP_MISC_FLAG_CONN_MASK corresponds with both _LOAD and _STORE.
66 /* .IP dest_prop
67 /* Destination specific session properties: the server is the
68 /* best MX host for the current logical destination, the dest,
69 /* host, and addr properties. When dest_prop is non-empty, it
70 /* overrides the iterator dest, host, and addr properties. It
71 /* is the caller's responsibility to save the current nexthop
72 /* with SMTP_ITER_SAVE_DEST() and to restore it afterwards
73 /* with SMTP_ITER_RESTORE_DEST() before trying alternatives.
74 /* .IP endp_prop
75 /* Endpoint specific session properties: all the features
76 /* advertised by the remote server.
77 /* LICENSE
78 /* .ad
79 /* .fi
80 /* The Secure Mailer license must be distributed with this software.
81 /* AUTHOR(S)
82 /* Wietse Venema
83 /* IBM T.J. Watson Research
84 /* P.O. Box 704
85 /* Yorktown Heights, NY 10598, USA
86 /*
87 /* Viktor Dukhovni
88 /*--*/
89 
90 /* System library. */
91 
92 #include <sys_defs.h>
93 #include <stdlib.h>
94 #include <string.h>
95 #include <netinet/in.h>
96 
97 /* Utility library. */
98 
99 #include <msg.h>
100 #include <mymalloc.h>
101 #include <vstring.h>
102 #include <vstream.h>
103 #include <stringops.h>
104 
105 /* Global library. */
106 
107 #include <mime_state.h>
108 #include <debug_peer.h>
109 #include <mail_params.h>
110 
111 /* Application-specific. */
112 
113 #include "smtp.h"
114 #include "smtp_sasl.h"
115 
116 /* smtp_session_alloc - allocate and initialize SMTP_SESSION structure */
117 
119  time_t start, int flags)
120 {
121  SMTP_SESSION *session;
122  const char *host = STR(iter->host);
123  const char *addr = STR(iter->addr);
124  unsigned port = iter->port;
125 
126  session = (SMTP_SESSION *) mymalloc(sizeof(*session));
127  session->stream = stream;
128  session->iterator = iter;
129  session->namaddr = concatenate(host, "[", addr, "]", (char *) 0);
130  session->helo = 0;
131  session->port = port;
132  session->features = 0;
133 
134  session->size_limit = 0;
135  session->error_mask = 0;
136  session->buffer = vstring_alloc(100);
137  session->scratch = vstring_alloc(100);
138  session->scratch2 = vstring_alloc(100);
139  smtp_chat_init(session);
140  session->mime_state = 0;
141 
142  if (session->port) {
143  vstring_sprintf(session->buffer, "%s:%d",
144  session->namaddr, ntohs(session->port));
145  session->namaddrport = mystrdup(STR(session->buffer));
146  } else
147  session->namaddrport = mystrdup(session->namaddr);
148 
149  session->send_proto_helo = 0;
150 
151  if (flags & SMTP_MISC_FLAG_CONN_STORE)
153  else
155  session->reuse_count = 0;
156  USE_NEWBORN_SESSION; /* He's not dead Jim! */
157 
158 #ifdef USE_SASL_AUTH
159  smtp_sasl_connect(session);
160 #endif
161 
162 #ifdef USE_TLS
163  session->tls_context = 0;
164  session->tls_retry_plain = 0;
165  session->tls_nexthop = 0;
166 #endif
167  session->state = 0;
168  debug_peer_check(host, addr);
169  return (session);
170 }
171 
172 /* smtp_session_free - destroy SMTP_SESSION structure and contents */
173 
175 {
176 #ifdef USE_TLS
177  if (session->stream) {
178  vstream_fflush(session->stream);
179  if (session->tls_context)
180  tls_client_stop(smtp_tls_ctx, session->stream,
181  var_smtp_starttls_tmout, 0, session->tls_context);
182  }
183 #endif
184  if (session->stream)
185  vstream_fclose(session->stream);
186  myfree(session->namaddr);
187  myfree(session->namaddrport);
188  if (session->helo)
189  myfree(session->helo);
190 
191  vstring_free(session->buffer);
192  vstring_free(session->scratch);
193  vstring_free(session->scratch2);
194 
195  if (session->history)
196  smtp_chat_reset(session);
197  if (session->mime_state)
198  mime_state_free(session->mime_state);
199 
200 #ifdef USE_SASL_AUTH
201  smtp_sasl_cleanup(session);
202 #endif
203 
205  myfree((void *) session);
206 }
207 
208 /* smtp_session_passivate - passivate an SMTP_SESSION object */
209 
210 int smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop,
211  VSTRING *endp_prop)
212 {
213  SMTP_ITERATOR *iter = session->iterator;
214  int fd;
215 
216  /*
217  * Encode the local-to-physical binding properties: whether or not this
218  * server is best MX host for the next-hop or fall-back logical
219  * destination (this information is needed for loop handling in
220  * smtp_proto()).
221  *
222  * XXX It would be nice to have a VSTRING to VSTREAM adapter so that we can
223  * serialize the properties with attr_print() instead of using ad-hoc,
224  * non-reusable, code and hard-coded format strings.
225  *
226  * TODO: save SASL username and password information so that we can
227  * correctly save a reused authenticated connection.
228  *
229  */
230  vstring_sprintf(dest_prop, "%s\n%s\n%s\n%u",
231  STR(iter->dest), STR(iter->host), STR(iter->addr),
233 
234  /*
235  * Encode the physical endpoint properties: all the session properties
236  * except for "session from cache", "best MX", or "RSET failure".
237  *
238  * XXX It would be nice to have a VSTRING to VSTREAM adapter so that we can
239  * serialize the properties with attr_print() instead of using obscure
240  * hard-coded format strings.
241  *
242  * XXX Should also record an absolute time when a session must be closed,
243  * how many non-delivering mail transactions there were during this
244  * session, and perhaps other statistics, so that we don't reuse a
245  * session too much.
246  *
247  * XXX Be sure to use unsigned types in the format string. Sign characters
248  * would be rejected by the alldig() test on the reading end.
249  */
250  vstring_sprintf(endp_prop, "%u\n%u\n%lu",
251  session->reuse_count,
253  (long) session->expire_time);
254 
255  /*
256  * Append the passivated SASL attributes.
257  */
258 #ifdef notdef
259  if (smtp_sasl_enable)
260  smtp_sasl_passivate(endp_prop, session);
261 #endif
262 
263  /*
264  * Salvage the underlying file descriptor, and destroy the session
265  * object.
266  */
267  fd = vstream_fileno(session->stream);
268  vstream_fdclose(session->stream);
269  session->stream = 0;
270  smtp_session_free(session);
271 
272  return (fd);
273 }
274 
275 /* smtp_session_activate - re-activate a passivated SMTP_SESSION object */
276 
278  VSTRING *dest_prop,
279  VSTRING *endp_prop)
280 {
281  const char *myname = "smtp_session_activate";
282  SMTP_SESSION *session;
283  char *dest_props;
284  char *endp_props;
285  const char *prop;
286  const char *dest;
287  const char *host;
288  const char *addr;
289  unsigned features; /* server features */
290  time_t expire_time; /* session re-use expiration time */
291  unsigned reuse_count; /* # times reused */
292 
293  /*
294  * XXX it would be nice to have a VSTRING to VSTREAM adapter so that we
295  * can de-serialize the properties with attr_scan(), instead of using
296  * ad-hoc, non-reusable code.
297  *
298  * XXX As a preliminary solution we use mystrtok(), but that function is not
299  * suitable for zero-length fields.
300  */
301  endp_props = STR(endp_prop);
302  if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
303  msg_warn("%s: bad cached session reuse count property", myname);
304  return (0);
305  }
306  reuse_count = atoi(prop);
307  if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
308  msg_warn("%s: bad cached session features property", myname);
309  return (0);
310  }
311  features = atoi(prop);
312  if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
313  msg_warn("%s: bad cached session expiration time property", myname);
314  return (0);
315  }
316 #ifdef MISSING_STRTOUL
317  expire_time = strtol(prop, 0, 10);
318 #else
319  expire_time = strtoul(prop, 0, 10);
320 #endif
321 
322  /*
323  * Clobber the iterator's current nexthop, host and address fields with
324  * cached-connection information. This is done when a session is looked
325  * up by request nexthop instead of address and port. It is the caller's
326  * responsibility to save and restore the request nexthop with
327  * SMTP_ITER_SAVE_DEST() and SMTP_ITER_RESTORE_DEST().
328  *
329  * TODO: Eliminate the duplication between SMTP_ITERATOR and SMTP_SESSION.
330  *
331  * TODO: restore SASL username and password information so that we can
332  * correctly save a reused authenticated connection.
333  */
334  if (dest_prop && VSTRING_LEN(dest_prop)) {
335  dest_props = STR(dest_prop);
336  if ((dest = mystrtok(&dest_props, "\n")) == 0) {
337  msg_warn("%s: missing cached session destination property", myname);
338  return (0);
339  }
340  if ((host = mystrtok(&dest_props, "\n")) == 0) {
341  msg_warn("%s: missing cached session hostname property", myname);
342  return (0);
343  }
344  if ((addr = mystrtok(&dest_props, "\n")) == 0) {
345  msg_warn("%s: missing cached session address property", myname);
346  return (0);
347  }
348  if ((prop = mystrtok(&dest_props, "\n")) == 0 || !alldig(prop)) {
349  msg_warn("%s: bad cached destination features property", myname);
350  return (0);
351  }
352  features |= atoi(prop);
353  SMTP_ITER_CLOBBER(iter, dest, host, addr);
354  }
355 
356  /*
357  * Allright, bundle up what we have sofar.
358  */
359 #define NO_FLAGS 0
360 
361  session = smtp_session_alloc(vstream_fdopen(fd, O_RDWR), iter,
362  (time_t) 0, NO_FLAGS);
363  session->features = (features | SMTP_FEATURE_FROM_CACHE);
364  CACHE_THIS_SESSION_UNTIL(expire_time);
365  session->reuse_count = ++reuse_count;
366 
367  if (msg_verbose)
368  msg_info("%s: dest=%s host=%s addr=%s port=%u features=0x%x, "
369  "ttl=%ld, reuse=%d",
370  myname, STR(iter->dest), STR(iter->host),
371  STR(iter->addr), ntohs(iter->port), features,
372  (long) (expire_time - time((time_t *) 0)),
373  reuse_count);
374 
375  /*
376  * Re-activate the SASL attributes.
377  */
378 #ifdef notdef
379  if (smtp_sasl_enable && smtp_sasl_activate(session, endp_props) < 0) {
380  vstream_fdclose(session->stream);
381  session->stream = 0;
382  smtp_session_free(session);
383  return (0);
384  }
385 #endif
386 
387  return (session);
388 }
int msg_verbose
Definition: msg.c:177
void myfree(void *ptr)
Definition: mymalloc.c:207
off_t size_limit
Definition: smtp.h:317
int debug_peer_check(const char *name, const char *addr)
Definition: debug_peer.c:109
unsigned port
Definition: smtp.h:56
char * mystrdup(const char *str)
Definition: mymalloc.c:225
#define USE_NEWBORN_SESSION
Definition: smtp.h:448
#define SMTP_MISC_FLAG_CONN_STORE
Definition: smtp.h:247
int var_smtp_starttls_tmout
void smtp_sasl_passivate(SMTP_SESSION *, VSTRING *)
SMTP_SESSION * smtp_session_activate(int fd, SMTP_ITERATOR *iter, VSTRING *dest_prop, VSTRING *endp_prop)
Definition: smtp_session.c:277
unsigned port
Definition: smtp.h:309
int alldig(const char *string)
Definition: alldig.c:38
char * mystrtok(char **src, const char *sep)
Definition: mystrtok.c:54
#define VSTRING_LEN(vp)
Definition: vstring.h:72
#define SMTP_FEATURE_FROM_CACHE
Definition: smtp.h:217
VSTRING * dest
Definition: smtp.h:53
int error_mask
Definition: smtp.h:320
void smtp_chat_init(SMTP_SESSION *)
Definition: smtp_chat.c:150
#define SMTP_FEATURE_DESTINATION_MASK
Definition: smtp.h:236
ARGV * history
Definition: smtp.h:319
int var_smtp_reuse_time
Definition: smtp.c:883
#define DONT_CACHE_THIS_SESSION
Definition: smtp.h:437
int reuse_count
Definition: smtp.h:326
MIME_STATE * mime_state_free(MIME_STATE *state)
Definition: mime_state.c:530
#define SMTP_FEATURE_ENDPOINT_MASK
Definition: smtp.h:229
VSTRING * host
Definition: smtp.h:54
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
#define CACHE_THIS_SESSION_UNTIL(when)
Definition: smtp.h:451
#define STR(x)
Definition: anvil.c:518
VSTRING * addr
Definition: smtp.h:55
void msg_warn(const char *fmt,...)
Definition: msg.c:215
int smtp_sasl_activate(SMTP_SESSION *, char *)
VSTREAM * stream
Definition: smtp.h:305
int send_proto_helo
Definition: smtp.h:323
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
void smtp_sasl_connect(SMTP_SESSION *)
void debug_peer_restore(void)
Definition: debug_peer.c:127
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
Definition: vstring.c:602
#define SMTP_ITER_CLOBBER(iter, _dest, _host, _addr)
Definition: smtp.h:74
struct MIME_STATE * mime_state
Definition: smtp.h:321
char * helo
Definition: smtp.h:308
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
char * concatenate(const char *arg0,...)
Definition: concatenate.c:42
VSTRING * scratch
Definition: smtp.h:313
SMTP_STATE * state
Definition: smtp.h:346
int smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop, VSTRING *endp_prop)
Definition: smtp_session.c:210
void smtp_sasl_cleanup(SMTP_SESSION *)
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
int vstream_fdclose(VSTREAM *stream)
Definition: vstream.c:1309
#define vstream_fileno(vp)
Definition: vstream.h:115
#define NO_FLAGS
char * namaddr
Definition: smtp.h:307
VSTRING * scratch2
Definition: smtp.h:314
void smtp_chat_reset(SMTP_SESSION *)
Definition: smtp_chat.c:157
void smtp_session_free(SMTP_SESSION *session)
Definition: smtp_session.c:174
VSTRING * buffer
Definition: smtp.h:312
int features
Definition: smtp.h:316
char * namaddrport
Definition: smtp.h:310
time_t expire_time
Definition: smtp.h:325
VSTREAM * vstream_fdopen(int fd, int flags)
Definition: vstream.c:1204
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
SMTP_SESSION * smtp_session_alloc(VSTREAM *stream, SMTP_ITERATOR *iter, time_t start, int flags)
Definition: smtp_session.c:118
void msg_info(const char *fmt,...)
Definition: msg.c:199
SMTP_ITERATOR * iterator
Definition: smtp.h:306