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