engine.c revision 98121
1/* 2 * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * 5 * By using this file, you agree to the terms and conditions set 6 * forth in the LICENSE file which can be found at the top level of 7 * the sendmail distribution. 8 * 9 */ 10 11#include <sm/gen.h> 12SM_RCSID("@(#)$Id: engine.c,v 8.109 2002/03/13 17:18:44 gshapiro Exp $") 13 14#include "libmilter.h" 15 16#if NETINET || NETINET6 17# include <arpa/inet.h> 18#endif /* NETINET || NETINET6 */ 19 20/* generic argument for functions in the command table */ 21struct arg_struct 22{ 23 size_t a_len; /* length of buffer */ 24 char *a_buf; /* argument string */ 25 int a_idx; /* index for macro array */ 26 SMFICTX_PTR a_ctx; /* context */ 27}; 28 29typedef struct arg_struct genarg; 30 31/* structure for commands received from MTA */ 32struct cmdfct_t 33{ 34 char cm_cmd; /* command */ 35 int cm_argt; /* type of arguments expected */ 36 int cm_next; /* next state */ 37 int cm_todo; /* what to do next */ 38 int cm_macros; /* index for macros */ 39 int (*cm_fct) __P((genarg *)); /* function to execute */ 40}; 41 42typedef struct cmdfct_t cmdfct; 43 44/* possible values for cm_argt */ 45#define CM_ARG0 0 /* no args */ 46#define CM_ARG1 1 /* one arg (string) */ 47#define CM_ARG2 2 /* two args (strings) */ 48#define CM_ARGA 4 /* one string and _SOCK_ADDR */ 49#define CM_ARGO 5 /* two integers */ 50#define CM_ARGV 8 /* \0 separated list of args, NULL-terminated */ 51#define CM_ARGN 9 /* \0 separated list of args (strings) */ 52 53/* possible values for cm_todo */ 54#define CT_CONT 0x0000 /* continue reading commands */ 55#define CT_IGNO 0x0001 /* continue even when error */ 56 57/* not needed right now, done via return code instead */ 58#define CT_KEEP 0x0004 /* keep buffer (contains symbols) */ 59#define CT_END 0x0008 /* start replying */ 60 61/* index in macro array: macros only for these commands */ 62#define CI_NONE (-1) 63#define CI_CONN 0 64#define CI_HELO 1 65#define CI_MAIL 2 66#define CI_RCPT 3 67#if CI_RCPT >= MAX_MACROS_ENTRIES 68ERROR: do not compile with CI_RCPT >= MAX_MACROS_ENTRIES 69#endif 70 71/* function prototypes */ 72static int st_abortfct __P((genarg *)); 73static int st_macros __P((genarg *)); 74static int st_optionneg __P((genarg *)); 75static int st_bodychunk __P((genarg *)); 76static int st_connectinfo __P((genarg *)); 77static int st_bodyend __P((genarg *)); 78static int st_helo __P((genarg *)); 79static int st_header __P((genarg *)); 80static int st_sender __P((genarg *)); 81static int st_rcpt __P((genarg *)); 82static int st_eoh __P((genarg *)); 83static int st_quit __P((genarg *)); 84static int sendreply __P((sfsistat, socket_t, struct timeval *, SMFICTX_PTR)); 85static void fix_stm __P((SMFICTX_PTR)); 86static bool trans_ok __P((int, int)); 87static char **dec_argv __P((char *, size_t)); 88static int dec_arg2 __P((char *, size_t, char **, char **)); 89 90/* states */ 91#define ST_NONE (-1) 92#define ST_INIT 0 /* initial state */ 93#define ST_OPTS 1 /* option negotiation */ 94#define ST_CONN 2 /* connection info */ 95#define ST_HELO 3 /* helo */ 96#define ST_MAIL 4 /* mail from */ 97#define ST_RCPT 5 /* rcpt to */ 98#define ST_HDRS 6 /* headers */ 99#define ST_EOHS 7 /* end of headers */ 100#define ST_BODY 8 /* body */ 101#define ST_ENDM 9 /* end of message */ 102#define ST_QUIT 10 /* quit */ 103#define ST_ABRT 11 /* abort */ 104#define ST_LAST ST_ABRT 105#define ST_SKIP 15 /* not a state but required for the state table */ 106 107/* in a mail transaction? must be before eom according to spec. */ 108#define ST_IN_MAIL(st) ((st) >= ST_MAIL && (st) < ST_ENDM) 109 110/* 111** set of next states 112** each state (ST_*) corresponds to bit in an int value (1 << state) 113** each state has a set of allowed transitions ('or' of bits of states) 114** so a state transition is valid if the mask of the next state 115** is set in the NX_* value 116** this function is coded in trans_ok(), see below. 117*/ 118 119#define MASK(x) (0x0001 << (x)) /* generate a bit "mask" for a state */ 120#define NX_INIT (MASK(ST_OPTS)) 121#define NX_OPTS (MASK(ST_CONN)) 122#define NX_CONN (MASK(ST_HELO) | MASK(ST_MAIL)) 123#define NX_HELO (MASK(ST_HELO) | MASK(ST_MAIL)) 124#define NX_MAIL (MASK(ST_RCPT) | MASK(ST_ABRT)) 125#define NX_RCPT (MASK(ST_HDRS) | MASK(ST_EOHS) | \ 126 MASK(ST_BODY) | MASK(ST_ENDM) | \ 127 MASK(ST_RCPT) | MASK(ST_ABRT)) 128#define NX_HDRS (MASK(ST_EOHS) | MASK(ST_HDRS) | MASK(ST_ABRT)) 129#define NX_EOHS (MASK(ST_BODY) | MASK(ST_ENDM) | MASK(ST_ABRT)) 130#define NX_BODY (MASK(ST_ENDM) | MASK(ST_BODY) | MASK(ST_ABRT)) 131#define NX_ENDM (MASK(ST_QUIT) | MASK(ST_MAIL)) 132#define NX_QUIT 0 133#define NX_ABRT 0 134#define NX_SKIP MASK(ST_SKIP) 135 136static int next_states[] = 137{ 138 NX_INIT, 139 NX_OPTS, 140 NX_CONN, 141 NX_HELO, 142 NX_MAIL, 143 NX_RCPT, 144 NX_HDRS, 145 NX_EOHS, 146 NX_BODY, 147 NX_ENDM, 148 NX_QUIT, 149 NX_ABRT 150}; 151 152/* commands received by milter */ 153static cmdfct cmds[] = 154{ 155{SMFIC_ABORT, CM_ARG0, ST_ABRT, CT_CONT, CI_NONE, st_abortfct }, 156{SMFIC_MACRO, CM_ARGV, ST_NONE, CT_KEEP, CI_NONE, st_macros }, 157{SMFIC_BODY, CM_ARG1, ST_BODY, CT_CONT, CI_NONE, st_bodychunk }, 158{SMFIC_CONNECT, CM_ARG2, ST_CONN, CT_CONT, CI_CONN, st_connectinfo }, 159{SMFIC_BODYEOB, CM_ARG1, ST_ENDM, CT_CONT, CI_NONE, st_bodyend }, 160{SMFIC_HELO, CM_ARG1, ST_HELO, CT_CONT, CI_HELO, st_helo }, 161{SMFIC_HEADER, CM_ARG2, ST_HDRS, CT_CONT, CI_NONE, st_header }, 162{SMFIC_MAIL, CM_ARGV, ST_MAIL, CT_CONT, CI_MAIL, st_sender }, 163{SMFIC_OPTNEG, CM_ARGO, ST_OPTS, CT_CONT, CI_NONE, st_optionneg }, 164{SMFIC_EOH, CM_ARG0, ST_EOHS, CT_CONT, CI_NONE, st_eoh }, 165{SMFIC_QUIT, CM_ARG0, ST_QUIT, CT_END, CI_NONE, st_quit }, 166{SMFIC_RCPT, CM_ARGV, ST_RCPT, CT_IGNO, CI_RCPT, st_rcpt } 167}; 168 169/* additional (internal) reply codes */ 170#define _SMFIS_KEEP 20 171#define _SMFIS_ABORT 21 172#define _SMFIS_OPTIONS 22 173#define _SMFIS_NOREPLY 23 174#define _SMFIS_FAIL (-1) 175#define _SMFIS_NONE (-2) 176 177/* 178** MI_ENGINE -- receive commands and process them 179** 180** Parameters: 181** ctx -- context structure 182** 183** Returns: 184** MI_FAILURE/MI_SUCCESS 185*/ 186int 187mi_engine(ctx) 188 SMFICTX_PTR ctx; 189{ 190 size_t len; 191 int i; 192 socket_t sd; 193 int ret = MI_SUCCESS; 194 int ncmds = sizeof(cmds) / sizeof(cmdfct); 195 int curstate = ST_INIT; 196 int newstate; 197 bool call_abort; 198 sfsistat r; 199 char cmd; 200 char *buf = NULL; 201 genarg arg; 202 struct timeval timeout; 203 int (*f) __P((genarg *)); 204 sfsistat (*fi_abort) __P((SMFICTX *)); 205 sfsistat (*fi_close) __P((SMFICTX *)); 206 207 arg.a_ctx = ctx; 208 sd = ctx->ctx_sd; 209 fi_abort = ctx->ctx_smfi->xxfi_abort; 210 mi_clr_macros(ctx, 0); 211 fix_stm(ctx); 212 r = _SMFIS_NONE; 213 do 214 { 215 /* call abort only if in a mail transaction */ 216 call_abort = ST_IN_MAIL(curstate); 217 timeout.tv_sec = ctx->ctx_timeout; 218 timeout.tv_usec = 0; 219 if (mi_stop() == MILTER_ABRT) 220 { 221 if (ctx->ctx_dbg > 3) 222 sm_dprintf("[%d] milter_abort\n", 223 (int) ctx->ctx_id); 224 ret = MI_FAILURE; 225 break; 226 } 227 228 /* 229 ** Notice: buf is allocated by mi_rd_cmd() and it will 230 ** usually be free()d after it has been used in f(). 231 ** However, if the function returns _SMFIS_KEEP then buf 232 ** contains macros and will not be free()d. 233 ** Hence r must be set to _SMFIS_NONE if a new buf is 234 ** allocated to avoid problem with housekeeping, esp. 235 ** if the code "break"s out of the loop. 236 */ 237 238 r = _SMFIS_NONE; 239 if ((buf = mi_rd_cmd(sd, &timeout, &cmd, &len, 240 ctx->ctx_smfi->xxfi_name)) == NULL && 241 cmd < SMFIC_VALIDCMD) 242 { 243 if (ctx->ctx_dbg > 5) 244 sm_dprintf("[%d] mi_engine: mi_rd_cmd error (%x)\n", 245 (int) ctx->ctx_id, (int) cmd); 246 247 /* 248 ** eof is currently treated as failure -> 249 ** abort() instead of close(), otherwise use: 250 ** if (cmd != SMFIC_EOF) 251 */ 252 253 ret = MI_FAILURE; 254 break; 255 } 256 if (ctx->ctx_dbg > 4) 257 sm_dprintf("[%d] got cmd '%c' len %d\n", 258 (int) ctx->ctx_id, cmd, len); 259 for (i = 0; i < ncmds; i++) 260 { 261 if (cmd == cmds[i].cm_cmd) 262 break; 263 } 264 if (i >= ncmds) 265 { 266 /* unknown command */ 267 if (ctx->ctx_dbg > 1) 268 sm_dprintf("[%d] cmd '%c' unknown\n", 269 (int) ctx->ctx_id, cmd); 270 ret = MI_FAILURE; 271 break; 272 } 273 if ((f = cmds[i].cm_fct) == NULL) 274 { 275 /* stop for now */ 276 if (ctx->ctx_dbg > 1) 277 sm_dprintf("[%d] cmd '%c' not impl\n", 278 (int) ctx->ctx_id, cmd); 279 ret = MI_FAILURE; 280 break; 281 } 282 283 /* is new state ok? */ 284 newstate = cmds[i].cm_next; 285 if (ctx->ctx_dbg > 5) 286 sm_dprintf("[%d] cur %x new %x nextmask %x\n", 287 (int) ctx->ctx_id, 288 curstate, newstate, next_states[curstate]); 289 290 if (newstate != ST_NONE && !trans_ok(curstate, newstate)) 291 { 292 if (ctx->ctx_dbg > 1) 293 sm_dprintf("[%d] abort: cur %d (%x) new %d (%x) next %x\n", 294 (int) ctx->ctx_id, 295 curstate, MASK(curstate), 296 newstate, MASK(newstate), 297 next_states[curstate]); 298 299 /* call abort only if in a mail transaction */ 300 if (fi_abort != NULL && call_abort) 301 (void) (*fi_abort)(ctx); 302 303 /* 304 ** try to reach the new state from HELO 305 ** if it can't be reached, ignore the command. 306 */ 307 308 curstate = ST_HELO; 309 if (!trans_ok(curstate, newstate)) 310 { 311 free(buf); 312 buf = NULL; 313 continue; 314 } 315 } 316 arg.a_len = len; 317 arg.a_buf = buf; 318 if (newstate != ST_NONE) 319 { 320 curstate = newstate; 321 ctx->ctx_state = curstate; 322 } 323 arg.a_idx = cmds[i].cm_macros; 324 325 /* call function to deal with command */ 326 r = (*f)(&arg); 327 if (r != _SMFIS_KEEP && buf != NULL) 328 { 329 free(buf); 330 buf = NULL; 331 } 332 if (sendreply(r, sd, &timeout, ctx) != MI_SUCCESS) 333 { 334 ret = MI_FAILURE; 335 break; 336 } 337 338 call_abort = ST_IN_MAIL(curstate); 339 if (r == SMFIS_ACCEPT) 340 { 341 /* accept mail, no further actions taken */ 342 curstate = ST_HELO; 343 } 344 else if (r == SMFIS_REJECT || r == SMFIS_DISCARD || 345 r == SMFIS_TEMPFAIL) 346 { 347 /* 348 ** further actions depend on current state 349 ** if the IGNO bit is set: "ignore" the error, 350 ** i.e., stay in the current state 351 */ 352 if (!bitset(CT_IGNO, cmds[i].cm_todo)) 353 curstate = ST_HELO; 354 } 355 else if (r == _SMFIS_ABORT) 356 { 357 if (ctx->ctx_dbg > 5) 358 sm_dprintf("[%d] function returned abort\n", 359 (int) ctx->ctx_id); 360 ret = MI_FAILURE; 361 break; 362 } 363 } while (!bitset(CT_END, cmds[i].cm_todo)); 364 365 if (ret != MI_SUCCESS) 366 { 367 /* call abort only if in a mail transaction */ 368 if (fi_abort != NULL && call_abort) 369 (void) (*fi_abort)(ctx); 370 } 371 372 /* close must always be called */ 373 if ((fi_close = ctx->ctx_smfi->xxfi_close) != NULL) 374 (void) (*fi_close)(ctx); 375 if (r != _SMFIS_KEEP && buf != NULL) 376 free(buf); 377 mi_clr_macros(ctx, 0); 378 return ret; 379} 380/* 381** SENDREPLY -- send a reply to the MTA 382** 383** Parameters: 384** r -- reply code 385** sd -- socket descriptor 386** timeout_ptr -- (ptr to) timeout to use for sending 387** ctx -- context structure 388** 389** Returns: 390** MI_SUCCESS/MI_FAILURE 391*/ 392 393static int 394sendreply(r, sd, timeout_ptr, ctx) 395 sfsistat r; 396 socket_t sd; 397 struct timeval *timeout_ptr; 398 SMFICTX_PTR ctx; 399{ 400 int ret = MI_SUCCESS; 401 402 switch (r) 403 { 404 case SMFIS_CONTINUE: 405 ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, 0); 406 break; 407 case SMFIS_TEMPFAIL: 408 case SMFIS_REJECT: 409 if (ctx->ctx_reply != NULL && 410 ((r == SMFIS_TEMPFAIL && *ctx->ctx_reply == '4') || 411 (r == SMFIS_REJECT && *ctx->ctx_reply == '5'))) 412 { 413 ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_REPLYCODE, 414 ctx->ctx_reply, 415 strlen(ctx->ctx_reply) + 1); 416 free(ctx->ctx_reply); 417 ctx->ctx_reply = NULL; 418 } 419 else 420 { 421 ret = mi_wr_cmd(sd, timeout_ptr, r == SMFIS_REJECT ? 422 SMFIR_REJECT : SMFIR_TEMPFAIL, NULL, 0); 423 } 424 break; 425 case SMFIS_DISCARD: 426 ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_DISCARD, NULL, 0); 427 break; 428 case SMFIS_ACCEPT: 429 ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_ACCEPT, NULL, 0); 430 break; 431 case _SMFIS_OPTIONS: 432 { 433 char buf[MILTER_OPTLEN]; 434 mi_int32 v; 435 436 v = htonl(ctx->ctx_smfi->xxfi_version); 437 (void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES); 438 v = htonl(ctx->ctx_smfi->xxfi_flags); 439 (void) memcpy(&(buf[MILTER_LEN_BYTES]), (void *) &v, 440 MILTER_LEN_BYTES); 441 v = htonl(ctx->ctx_pflags); 442 (void) memcpy(&(buf[MILTER_LEN_BYTES * 2]), (void *) &v, 443 MILTER_LEN_BYTES); 444 ret = mi_wr_cmd(sd, timeout_ptr, SMFIC_OPTNEG, buf, 445 MILTER_OPTLEN); 446 } 447 break; 448 default: /* don't send a reply */ 449 break; 450 } 451 return ret; 452} 453 454/* 455** CLR_MACROS -- clear set of macros starting from a given index 456** 457** Parameters: 458** ctx -- context structure 459** m -- index from which to clear all macros 460** 461** Returns: 462** None. 463*/ 464void 465mi_clr_macros(ctx, m) 466 SMFICTX_PTR ctx; 467 int m; 468{ 469 int i; 470 471 for (i = m; i < MAX_MACROS_ENTRIES; i++) 472 { 473 if (ctx->ctx_mac_ptr[i] != NULL) 474 { 475 free(ctx->ctx_mac_ptr[i]); 476 ctx->ctx_mac_ptr[i] = NULL; 477 } 478 if (ctx->ctx_mac_buf[i] != NULL) 479 { 480 free(ctx->ctx_mac_buf[i]); 481 ctx->ctx_mac_buf[i] = NULL; 482 } 483 } 484} 485/* 486** ST_OPTIONNEG -- negotiate options 487** 488** Parameters: 489** g -- generic argument structure 490** 491** Returns: 492** abort/send options/continue 493*/ 494 495static int 496st_optionneg(g) 497 genarg *g; 498{ 499 mi_int32 i, v; 500 501 if (g == NULL || g->a_ctx->ctx_smfi == NULL) 502 return SMFIS_CONTINUE; 503 mi_clr_macros(g->a_ctx, g->a_idx + 1); 504 505 /* check for minimum length */ 506 if (g->a_len < MILTER_OPTLEN) 507 { 508 smi_log(SMI_LOG_ERR, 509 "%s: st_optionneg[%d]: len too short %d < %d", 510 g->a_ctx->ctx_smfi->xxfi_name, 511 (int) g->a_ctx->ctx_id, g->a_len, 512 MILTER_OPTLEN); 513 return _SMFIS_ABORT; 514 } 515 516 (void) memcpy((void *) &i, (void *) &(g->a_buf[0]), 517 MILTER_LEN_BYTES); 518 v = ntohl(i); 519 if (v < g->a_ctx->ctx_smfi->xxfi_version) 520 { 521 /* hard failure for now! */ 522 smi_log(SMI_LOG_ERR, 523 "%s: st_optionneg[%d]: version mismatch MTA: %d < milter: %d", 524 g->a_ctx->ctx_smfi->xxfi_name, 525 (int) g->a_ctx->ctx_id, (int) v, 526 g->a_ctx->ctx_smfi->xxfi_version); 527 return _SMFIS_ABORT; 528 } 529 530 (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES]), 531 MILTER_LEN_BYTES); 532 v = ntohl(i); 533 534 /* no flags? set to default value for V1 actions */ 535 if (v == 0) 536 v = SMFI_V1_ACTS; 537 i = g->a_ctx->ctx_smfi->xxfi_flags; 538 if ((v & i) != i) 539 { 540 smi_log(SMI_LOG_ERR, 541 "%s: st_optionneg[%d]: 0x%x does not fulfill action requirements 0x%x", 542 g->a_ctx->ctx_smfi->xxfi_name, 543 (int) g->a_ctx->ctx_id, v, i); 544 return _SMFIS_ABORT; 545 } 546 547 (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES * 2]), 548 MILTER_LEN_BYTES); 549 v = ntohl(i); 550 551 /* no flags? set to default value for V1 protocol */ 552 if (v == 0) 553 v = SMFI_V1_PROT; 554 i = g->a_ctx->ctx_pflags; 555 if ((v & i) != i) 556 { 557 smi_log(SMI_LOG_ERR, 558 "%s: st_optionneg[%d]: 0x%x does not fulfill protocol requirements 0x%x", 559 g->a_ctx->ctx_smfi->xxfi_name, 560 (int) g->a_ctx->ctx_id, v, i); 561 return _SMFIS_ABORT; 562 } 563 564 return _SMFIS_OPTIONS; 565} 566/* 567** ST_CONNECTINFO -- receive connection information 568** 569** Parameters: 570** g -- generic argument structure 571** 572** Returns: 573** continue or filter-specified value 574*/ 575 576static int 577st_connectinfo(g) 578 genarg *g; 579{ 580 size_t l; 581 size_t i; 582 char *s, family; 583 unsigned short port = 0; 584 _SOCK_ADDR sockaddr; 585 sfsistat (*fi_connect) __P((SMFICTX *, char *, _SOCK_ADDR *)); 586 587 if (g == NULL) 588 return _SMFIS_ABORT; 589 mi_clr_macros(g->a_ctx, g->a_idx + 1); 590 if (g->a_ctx->ctx_smfi == NULL || 591 (fi_connect = g->a_ctx->ctx_smfi->xxfi_connect) == NULL) 592 return SMFIS_CONTINUE; 593 594 s = g->a_buf; 595 i = 0; 596 l = g->a_len; 597 while (s[i] != '\0' && i <= l) 598 ++i; 599 if (i >= l) 600 return _SMFIS_ABORT; 601 602 /* Move past trailing \0 in host string */ 603 i++; 604 family = s[i++]; 605 memset(&sockaddr, '\0', sizeof sockaddr); 606 if (family != SMFIA_UNKNOWN) 607 { 608 (void) memcpy((void *) &port, (void *) (s + i), 609 sizeof port); 610 if ((i += sizeof port) >= l) 611 { 612 smi_log(SMI_LOG_ERR, 613 "%s: connect[%d]: wrong len %d >= %d", 614 g->a_ctx->ctx_smfi->xxfi_name, 615 (int) g->a_ctx->ctx_id, i, l); 616 return _SMFIS_ABORT; 617 } 618 619 /* make sure string is terminated */ 620 if (s[l - 1] != '\0') 621 return _SMFIS_ABORT; 622# if NETINET 623 if (family == SMFIA_INET) 624 { 625 if (inet_aton(s + i, (struct in_addr *) &sockaddr.sin.sin_addr) 626 != 1) 627 { 628 smi_log(SMI_LOG_ERR, 629 "%s: connect[%d]: inet_aton failed", 630 g->a_ctx->ctx_smfi->xxfi_name, 631 (int) g->a_ctx->ctx_id); 632 return _SMFIS_ABORT; 633 } 634 sockaddr.sa.sa_family = AF_INET; 635 if (port > 0) 636 sockaddr.sin.sin_port = port; 637 } 638 else 639# endif /* NETINET */ 640# if NETINET6 641 if (family == SMFIA_INET6) 642 { 643 if (mi_inet_pton(AF_INET6, s + i, 644 &sockaddr.sin6.sin6_addr) != 1) 645 { 646 smi_log(SMI_LOG_ERR, 647 "%s: connect[%d]: mi_inet_pton failed", 648 g->a_ctx->ctx_smfi->xxfi_name, 649 (int) g->a_ctx->ctx_id); 650 return _SMFIS_ABORT; 651 } 652 sockaddr.sa.sa_family = AF_INET6; 653 if (port > 0) 654 sockaddr.sin6.sin6_port = port; 655 } 656 else 657# endif /* NETINET6 */ 658# if NETUNIX 659 if (family == SMFIA_UNIX) 660 { 661 if (sm_strlcpy(sockaddr.sunix.sun_path, s + i, 662 sizeof sockaddr.sunix.sun_path) >= 663 sizeof sockaddr.sunix.sun_path) 664 { 665 smi_log(SMI_LOG_ERR, 666 "%s: connect[%d]: path too long", 667 g->a_ctx->ctx_smfi->xxfi_name, 668 (int) g->a_ctx->ctx_id); 669 return _SMFIS_ABORT; 670 } 671 sockaddr.sunix.sun_family = AF_UNIX; 672 } 673 else 674# endif /* NETUNIX */ 675 { 676 smi_log(SMI_LOG_ERR, 677 "%s: connect[%d]: unknown family %d", 678 g->a_ctx->ctx_smfi->xxfi_name, 679 (int) g->a_ctx->ctx_id, family); 680 return _SMFIS_ABORT; 681 } 682 } 683 return (*fi_connect)(g->a_ctx, g->a_buf, 684 family != SMFIA_UNKNOWN ? &sockaddr : NULL); 685} 686/* 687** ST_EOH -- end of headers 688** 689** Parameters: 690** g -- generic argument structure 691** 692** Returns: 693** continue or filter-specified value 694*/ 695 696static int 697st_eoh(g) 698 genarg *g; 699{ 700 sfsistat (*fi_eoh) __P((SMFICTX *)); 701 702 if (g == NULL) 703 return _SMFIS_ABORT; 704 if (g->a_ctx->ctx_smfi != NULL && 705 (fi_eoh = g->a_ctx->ctx_smfi->xxfi_eoh) != NULL) 706 return (*fi_eoh)(g->a_ctx); 707 return SMFIS_CONTINUE; 708} 709/* 710** ST_HELO -- helo/ehlo command 711** 712** Parameters: 713** g -- generic argument structure 714** 715** Returns: 716** continue or filter-specified value 717*/ 718static int 719st_helo(g) 720 genarg *g; 721{ 722 sfsistat (*fi_helo) __P((SMFICTX *, char *)); 723 724 if (g == NULL) 725 return _SMFIS_ABORT; 726 mi_clr_macros(g->a_ctx, g->a_idx + 1); 727 if (g->a_ctx->ctx_smfi != NULL && 728 (fi_helo = g->a_ctx->ctx_smfi->xxfi_helo) != NULL) 729 return (*fi_helo)(g->a_ctx, g->a_buf); 730 return SMFIS_CONTINUE; 731} 732/* 733** ST_HEADER -- header line 734** 735** Parameters: 736** g -- generic argument structure 737** 738** Returns: 739** continue or filter-specified value 740*/ 741 742static int 743st_header(g) 744 genarg *g; 745{ 746 char *hf, *hv; 747 sfsistat (*fi_header) __P((SMFICTX *, char *, char *)); 748 749 if (g == NULL) 750 return _SMFIS_ABORT; 751 if (g->a_ctx->ctx_smfi == NULL || 752 (fi_header = g->a_ctx->ctx_smfi->xxfi_header) == NULL) 753 return SMFIS_CONTINUE; 754 if (dec_arg2(g->a_buf, g->a_len, &hf, &hv) == MI_SUCCESS) 755 return (*fi_header)(g->a_ctx, hf, hv); 756 else 757 return _SMFIS_ABORT; 758} 759 760#define ARGV_FCT(lf, rf, idx) \ 761 char **argv; \ 762 sfsistat (*lf) __P((SMFICTX *, char **)); \ 763 int r; \ 764 \ 765 if (g == NULL) \ 766 return _SMFIS_ABORT; \ 767 mi_clr_macros(g->a_ctx, g->a_idx + 1); \ 768 if (g->a_ctx->ctx_smfi == NULL || \ 769 (lf = g->a_ctx->ctx_smfi->rf) == NULL) \ 770 return SMFIS_CONTINUE; \ 771 if ((argv = dec_argv(g->a_buf, g->a_len)) == NULL) \ 772 return _SMFIS_ABORT; \ 773 r = (*lf)(g->a_ctx, argv); \ 774 free(argv); \ 775 return r; 776 777/* 778** ST_SENDER -- MAIL FROM command 779** 780** Parameters: 781** g -- generic argument structure 782** 783** Returns: 784** continue or filter-specified value 785*/ 786 787static int 788st_sender(g) 789 genarg *g; 790{ 791 ARGV_FCT(fi_envfrom, xxfi_envfrom, CI_MAIL) 792} 793/* 794** ST_RCPT -- RCPT TO command 795** 796** Parameters: 797** g -- generic argument structure 798** 799** Returns: 800** continue or filter-specified value 801*/ 802 803static int 804st_rcpt(g) 805 genarg *g; 806{ 807 ARGV_FCT(fi_envrcpt, xxfi_envrcpt, CI_RCPT) 808} 809/* 810** ST_MACROS -- deal with macros received from the MTA 811** 812** Parameters: 813** g -- generic argument structure 814** 815** Returns: 816** continue/keep 817** 818** Side effects: 819** set pointer in macro array to current values. 820*/ 821 822static int 823st_macros(g) 824 genarg *g; 825{ 826 int i; 827 char **argv; 828 829 if (g == NULL || g->a_len < 1) 830 return _SMFIS_FAIL; 831 if ((argv = dec_argv(g->a_buf + 1, g->a_len - 1)) == NULL) 832 return _SMFIS_FAIL; 833 switch (g->a_buf[0]) 834 { 835 case SMFIC_CONNECT: 836 i = CI_CONN; 837 break; 838 case SMFIC_HELO: 839 i = CI_HELO; 840 break; 841 case SMFIC_MAIL: 842 i = CI_MAIL; 843 break; 844 case SMFIC_RCPT: 845 i = CI_RCPT; 846 break; 847 default: 848 free(argv); 849 return _SMFIS_FAIL; 850 } 851 if (g->a_ctx->ctx_mac_ptr[i] != NULL) 852 free(g->a_ctx->ctx_mac_ptr[i]); 853 if (g->a_ctx->ctx_mac_buf[i] != NULL) 854 free(g->a_ctx->ctx_mac_buf[i]); 855 g->a_ctx->ctx_mac_ptr[i] = argv; 856 g->a_ctx->ctx_mac_buf[i] = g->a_buf; 857 return _SMFIS_KEEP; 858} 859/* 860** ST_QUIT -- quit command 861** 862** Parameters: 863** g -- generic argument structure 864** 865** Returns: 866** noreply 867*/ 868 869static int 870st_quit(g) 871 genarg *g; 872{ 873 return _SMFIS_NOREPLY; 874} 875/* 876** ST_BODYCHUNK -- deal with a piece of the mail body 877** 878** Parameters: 879** g -- generic argument structure 880** 881** Returns: 882** continue or filter-specified value 883*/ 884 885static int 886st_bodychunk(g) 887 genarg *g; 888{ 889 sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t)); 890 891 if (g == NULL) 892 return _SMFIS_ABORT; 893 if (g->a_ctx->ctx_smfi != NULL && 894 (fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL) 895 return (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf, 896 g->a_len); 897 return SMFIS_CONTINUE; 898} 899/* 900** ST_BODYEND -- deal with the last piece of the mail body 901** 902** Parameters: 903** g -- generic argument structure 904** 905** Returns: 906** continue or filter-specified value 907** 908** Side effects: 909** sends a reply for the body part (if non-empty). 910*/ 911 912static int 913st_bodyend(g) 914 genarg *g; 915{ 916 sfsistat r; 917 sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t)); 918 sfsistat (*fi_eom) __P((SMFICTX *)); 919 920 if (g == NULL) 921 return _SMFIS_ABORT; 922 r = SMFIS_CONTINUE; 923 if (g->a_ctx->ctx_smfi != NULL) 924 { 925 if ((fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL && 926 g->a_len > 0) 927 { 928 socket_t sd; 929 struct timeval timeout; 930 931 timeout.tv_sec = g->a_ctx->ctx_timeout; 932 timeout.tv_usec = 0; 933 sd = g->a_ctx->ctx_sd; 934 r = (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf, 935 g->a_len); 936 if (r != SMFIS_CONTINUE && 937 sendreply(r, sd, &timeout, g->a_ctx) != MI_SUCCESS) 938 return _SMFIS_ABORT; 939 } 940 } 941 if (r == SMFIS_CONTINUE && 942 (fi_eom = g->a_ctx->ctx_smfi->xxfi_eom) != NULL) 943 return (*fi_eom)(g->a_ctx); 944 return r; 945} 946/* 947** ST_ABORTFCT -- deal with aborts 948** 949** Parameters: 950** g -- generic argument structure 951** 952** Returns: 953** abort or filter-specified value 954*/ 955 956static int 957st_abortfct(g) 958 genarg *g; 959{ 960 sfsistat (*fi_abort) __P((SMFICTX *)); 961 962 if (g == NULL) 963 return _SMFIS_ABORT; 964 if (g != NULL && g->a_ctx->ctx_smfi != NULL && 965 (fi_abort = g->a_ctx->ctx_smfi->xxfi_abort) != NULL) 966 (void) (*fi_abort)(g->a_ctx); 967 return _SMFIS_NOREPLY; 968} 969/* 970** TRANS_OK -- is the state transition ok? 971** 972** Parameters: 973** old -- old state 974** new -- new state 975** 976** Returns: 977** state transition ok 978*/ 979 980static bool 981trans_ok(old, new) 982 int old, new; 983{ 984 int s, n; 985 986 s = old; 987 do 988 { 989 /* is this state transition allowed? */ 990 if ((MASK(new) & next_states[s]) != 0) 991 return true; 992 993 /* 994 ** no: try next state; 995 ** this works since the relevant states are ordered 996 ** strict sequentially 997 */ 998 999 n = s + 1; 1000 1001 /* 1002 ** can we actually "skip" this state? 1003 ** see fix_stm() which sets this bit for those 1004 ** states which the filter program is not interested in 1005 */ 1006 1007 if (bitset(NX_SKIP, next_states[n])) 1008 s = n; 1009 else 1010 return false; 1011 } while (s <= ST_LAST); 1012 return false; 1013} 1014/* 1015** FIX_STM -- add "skip" bits to the state transition table 1016** 1017** Parameters: 1018** ctx -- context structure 1019** 1020** Returns: 1021** None. 1022** 1023** Side effects: 1024** may change state transition table. 1025*/ 1026 1027static void 1028fix_stm(ctx) 1029 SMFICTX_PTR ctx; 1030{ 1031 unsigned long fl; 1032 1033 if (ctx == NULL || ctx->ctx_smfi == NULL) 1034 return; 1035 fl = ctx->ctx_pflags; 1036 if (bitset(SMFIP_NOCONNECT, fl)) 1037 next_states[ST_CONN] |= NX_SKIP; 1038 if (bitset(SMFIP_NOHELO, fl)) 1039 next_states[ST_HELO] |= NX_SKIP; 1040 if (bitset(SMFIP_NOMAIL, fl)) 1041 next_states[ST_MAIL] |= NX_SKIP; 1042 if (bitset(SMFIP_NORCPT, fl)) 1043 next_states[ST_RCPT] |= NX_SKIP; 1044 if (bitset(SMFIP_NOHDRS, fl)) 1045 next_states[ST_HDRS] |= NX_SKIP; 1046 if (bitset(SMFIP_NOEOH, fl)) 1047 next_states[ST_EOHS] |= NX_SKIP; 1048 if (bitset(SMFIP_NOBODY, fl)) 1049 next_states[ST_BODY] |= NX_SKIP; 1050} 1051/* 1052** DEC_ARGV -- split a buffer into a list of strings, NULL terminated 1053** 1054** Parameters: 1055** buf -- buffer with several strings 1056** len -- length of buffer 1057** 1058** Returns: 1059** array of pointers to the individual strings 1060*/ 1061 1062static char ** 1063dec_argv(buf, len) 1064 char *buf; 1065 size_t len; 1066{ 1067 char **s; 1068 size_t i; 1069 int elem, nelem; 1070 1071 nelem = 0; 1072 for (i = 0; i < len; i++) 1073 { 1074 if (buf[i] == '\0') 1075 ++nelem; 1076 } 1077 if (nelem == 0) 1078 return NULL; 1079 1080 /* last entry is only for the name */ 1081 s = (char **)malloc((nelem + 1) * (sizeof *s)); 1082 if (s == NULL) 1083 return NULL; 1084 s[0] = buf; 1085 for (i = 0, elem = 0; i < len && elem < nelem; i++) 1086 { 1087 if (buf[i] == '\0') 1088 s[++elem] = &(buf[i + 1]); 1089 } 1090 1091 /* overwrite last entry */ 1092 s[elem] = NULL; 1093 return s; 1094} 1095/* 1096** DEC_ARG2 -- split a buffer into two strings 1097** 1098** Parameters: 1099** buf -- buffer with two strings 1100** len -- length of buffer 1101** s1,s2 -- pointer to result strings 1102** 1103** Returns: 1104** MI_FAILURE/MI_SUCCESS 1105*/ 1106 1107static int 1108dec_arg2(buf, len, s1, s2) 1109 char *buf; 1110 size_t len; 1111 char **s1; 1112 char **s2; 1113{ 1114 size_t i; 1115 1116 *s1 = buf; 1117 for (i = 1; i < len && buf[i] != '\0'; i++) 1118 continue; 1119 if (i >= len - 1) 1120 return MI_FAILURE; 1121 *s2 = buf + i + 1; 1122 return MI_SUCCESS; 1123} 1124/* 1125** SENDOK -- is it ok for the filter to send stuff to the MTA? 1126** 1127** Parameters: 1128** ctx -- context structure 1129** flag -- flag to check 1130** 1131** Returns: 1132** sending allowed (in current state) 1133*/ 1134 1135bool 1136mi_sendok(ctx, flag) 1137 SMFICTX_PTR ctx; 1138 int flag; 1139{ 1140 if (ctx == NULL || ctx->ctx_smfi == NULL) 1141 return false; 1142 1143 /* did the milter request this operation? */ 1144 if (flag != 0 && !bitset(flag, ctx->ctx_smfi->xxfi_flags)) 1145 return false; 1146 1147 /* are we in the correct state? It must be "End of Message". */ 1148 return ctx->ctx_state == ST_ENDM; 1149} 1150