root/sapi/milter/php_milter.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ZEND_BEGIN_MODULE_GLOBALS
  2. mlfi_connect
  3. mlfi_helo
  4. mlfi_envfrom
  5. mlfi_envrcpt
  6. mlfi_header
  7. mlfi_eoh
  8. mlfi_body
  9. mlfi_eom
  10. mlfi_abort
  11. mlfi_close
  12. PHP_FUNCTION
  13. PHP_FUNCTION
  14. PHP_FUNCTION
  15. PHP_FUNCTION
  16. PHP_FUNCTION
  17. PHP_FUNCTION
  18. PHP_FUNCTION
  19. PHP_FUNCTION
  20. PHP_FUNCTION
  21. PHP_MINIT_FUNCTION
  22. PHP_MINFO_FUNCTION
  23. sapi_milter_ub_write
  24. sapi_milter_flush
  25. sapi_milter_register_variables
  26. sapi_milter_post_read
  27. sapi_milter_read_cookies
  28. sapi_milter_send_headers
  29. php_milter_startup
  30. php_milter_usage
  31. define_command_line_ini_entry
  32. main

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 5                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Author: Harald Radi <phanto@php.net>                                 |
  16    |         Parts based on CGI SAPI Module by                            |
  17    |         Rasmus Lerdorf, Stig Bakken and Zeev Suraski                 |
  18    +----------------------------------------------------------------------+
  19 */
  20 
  21 /* $Id$ */
  22 
  23 #include "php.h"
  24 #include "php_globals.h"
  25 #include "php_variables.h"
  26 #include "zend_modules.h"
  27 
  28 #ifndef ZTS
  29 #error SRM sapi module is only useable in thread-safe mode
  30 #endif
  31 
  32 #include "SAPI.h"
  33 
  34 #include <stdio.h>
  35 #include "php.h"
  36 #if HAVE_SYS_TIME_H
  37 #include <sys/time.h>
  38 #endif
  39 #if HAVE_UNISTD_H
  40 #include <unistd.h>
  41 #endif
  42 #if HAVE_SIGNAL_H
  43 #include <signal.h>
  44 #endif
  45 #if HAVE_SETLOCALE
  46 #include <locale.h>
  47 #endif
  48 #include "zend.h"
  49 #include "zend_extensions.h"
  50 #include "php_ini.h"
  51 #include "php_globals.h"
  52 #include "php_main.h"
  53 #include "fopen_wrappers.h"
  54 #include "ext/standard/php_standard.h"
  55 
  56 #ifdef __riscos__
  57 #include <unixlib/local.h>
  58 #endif
  59 
  60 #include "zend_compile.h"
  61 #include "zend_execute.h"
  62 #include "zend_highlight.h"
  63 #include "zend_indent.h"
  64 
  65 #include "libmilter/mfapi.h"
  66 
  67 #include "php_getopt.h"
  68 
  69 #define OPTSTRING "ac:d:Def:hnp:vVz:?"
  70 #define MG(v)  TSRMG(milter_globals_id, zend_milter_globals *, v)
  71 
  72 #define IS_NONE "%s(): This function must not be called outside of a milter callback function's scope"
  73 #define NOT_EOM "%s(): This function can only be used inside the milter_eom callback's scope"
  74 #define NOT_INIT "%s(): This function can only be used inside the milter_init callback's scope"
  75 
  76 #define MLFI_NONE               0
  77 #define MLFI_CONNECT    1
  78 #define MLFI_HELO               2
  79 #define MLFI_ENVFROM    3
  80 #define MLFI_ENVRCPT    4
  81 #define MLFI_HEADER             5
  82 #define MLFI_EOH                6
  83 #define MLFI_BODY               7
  84 #define MLFI_EOM                8
  85 #define MLFI_ABORT              9
  86 #define MLFI_CLOSE              10
  87 #define MLFI_INIT               11
  88 
  89 /* {{{ globals
  90  */
  91 extern char *ap_php_optarg;
  92 extern int ap_php_optind;
  93 
  94 static int flag_debug=0;
  95 static char *filename = NULL;
  96 
  97 /* per thread */
  98 ZEND_BEGIN_MODULE_GLOBALS(milter)
  99         SMFICTX *ctx;
 100         int state;
 101         int initialized;
 102 ZEND_END_MODULE_GLOBALS(milter)
 103 
 104 ZEND_DECLARE_MODULE_GLOBALS(milter)
 105 /* }}} */
 106 
 107 /* this method is called only once when the milter starts */
 108 /* {{{ Init Milter
 109 */
 110 static int mlfi_init()
 111 {
 112         int ret = 0;
 113         zend_file_handle file_handle;
 114         zval function_name, retval;
 115         int status;
 116         TSRMLS_FETCH();
 117 
 118         /* request startup */
 119         if (php_request_startup(TSRMLS_C)==FAILURE) {
 120                 SG(headers_sent) = 1;
 121                 SG(request_info).no_headers = 1;
 122                 php_request_shutdown((void *) 0);
 123 
 124                 return -1;
 125         }
 126         
 127         /* disable headers */
 128         SG(headers_sent) = 1;
 129         SG(request_info).no_headers = 1;
 130          
 131         if (filename == NULL) {
 132                 php_printf("No input file specified");
 133                 return SMFIS_TEMPFAIL;
 134         }
 135 
 136         if (!(file_handle.handle.fp = VCWD_FOPEN(filename, "rb"))) {
 137                 php_printf("Could not open input file: %s\n", filename);
 138                 return SMFIS_TEMPFAIL;
 139         }
 140 
 141         file_handle.type = ZEND_HANDLE_FP;
 142         file_handle.filename = filename;
 143         file_handle.free_filename = 0;
 144         file_handle.opened_path = NULL;
 145 
 146         php_execute_script(&file_handle TSRMLS_CC);
 147         
 148         /* call userland */
 149         INIT_ZVAL(function_name);
 150 
 151         ZVAL_STRING(&function_name, "milter_init", 0);
 152 
 153         /* set the milter context for possible use in API functions */
 154         MG(state) = MLFI_INIT;
 155 
 156         status = call_user_function(CG(function_table), NULL, &function_name, &retval, 0, NULL TSRMLS_CC);
 157 
 158         MG(state) = MLFI_NONE;
 159         MG(initialized) = 1;
 160 
 161         if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
 162                 ret = Z_LVAL(retval);
 163         }
 164         
 165         php_request_shutdown((void *) 0);
 166         
 167         return ret;
 168 }
 169 /* }}} */
 170 
 171 /* {{{ Milter callback functions
 172  */
 173 
 174 /* connection info filter, is called whenever sendmail connects to the milter */
 175 /* {{{ mlfi_connect()
 176 */
 177 static sfsistat mlfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr)
 178 {
 179         zend_file_handle file_handle;
 180         zval function_name, retval, *param[1];
 181         int status;
 182         TSRMLS_FETCH();
 183 
 184         /* request startup */
 185         if (php_request_startup(TSRMLS_C)==FAILURE) {
 186                 SG(headers_sent) = 1;
 187                 SG(request_info).no_headers = 1;
 188                 php_request_shutdown((void *) 0);
 189 
 190                 return SMFIS_TEMPFAIL;
 191         }
 192         
 193         /* disable headers */
 194         SG(headers_sent) = 1;
 195         SG(request_info).no_headers = 1;
 196         
 197         if (filename == NULL) {
 198                 php_printf("No input file specified");
 199                 return SMFIS_TEMPFAIL;
 200         }
 201         
 202         if (!(file_handle.handle.fp = VCWD_FOPEN(filename, "rb"))) {
 203                 php_printf("Could not open input file: %s\n", filename);
 204                 return SMFIS_TEMPFAIL;
 205         }
 206 
 207         file_handle.type = ZEND_HANDLE_FP;
 208         file_handle.filename = filename;
 209         file_handle.free_filename = 0;
 210         file_handle.opened_path = NULL;
 211 
 212         php_execute_script(&file_handle TSRMLS_CC);
 213         
 214         /* call userland */
 215         INIT_ZVAL(function_name);
 216 
 217         ALLOC_ZVAL(param[0]);
 218         INIT_PZVAL(param[0]);
 219 
 220         ZVAL_STRING(&function_name, "milter_connect", 0);
 221         ZVAL_STRING(param[0], hostname, 1);
 222 
 223         /* set the milter context for possible use in API functions */
 224         MG(ctx) = ctx;
 225         MG(state) = MLFI_CONNECT;
 226 
 227         status = call_user_function(CG(function_table), NULL, &function_name, &retval, 1, param TSRMLS_CC);
 228 
 229         MG(state) = MLFI_NONE;
 230         zval_ptr_dtor(param);
 231         if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
 232                 return Z_LVAL(retval);
 233         }
 234         
 235         return SMFIS_CONTINUE;
 236 }
 237 /* }}} */
 238 
 239 /* SMTP HELO command filter */
 240 /* {{{ mlfi_helo()
 241 */
 242 static sfsistat mlfi_helo(SMFICTX *ctx, char *helohost)
 243 {
 244         zval function_name, retval, *param[1];
 245         int status;
 246         TSRMLS_FETCH();
 247 
 248         /* call userland */
 249         INIT_ZVAL(function_name);
 250         
 251         ALLOC_ZVAL(param[0]);
 252         INIT_PZVAL(param[0]);
 253 
 254         ZVAL_STRING(&function_name, "milter_helo", 0);
 255         ZVAL_STRING(param[0], helohost, 1);
 256 
 257         /* set the milter context for possible use in API functions */
 258         MG(ctx) = ctx;
 259         MG(state) = MLFI_HELO;
 260         
 261         status = call_user_function(CG(function_table), NULL, &function_name, &retval, 1, param TSRMLS_CC);
 262 
 263         MG(state) = MLFI_NONE;
 264         zval_ptr_dtor(param);
 265         
 266         if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
 267                 return Z_LVAL(retval);
 268         }
 269         
 270         return SMFIS_CONTINUE;
 271 }
 272 /* }}} */
 273 
 274 /* envelope sender filter */
 275 /* {{{ mlfi_envform()
 276 */
 277 static sfsistat mlfi_envfrom(SMFICTX *ctx, char **argv)
 278 {
 279         zval function_name, retval, *param[1];
 280         int status;
 281         TSRMLS_FETCH();
 282 
 283         /* call userland */
 284         INIT_ZVAL(function_name);
 285         
 286         ALLOC_ZVAL(param[0]);
 287         INIT_PZVAL(param[0]);
 288 
 289         ZVAL_STRING(&function_name, "milter_envfrom", 0);
 290         array_init(param[0]);
 291 
 292         while (*argv) {
 293                 add_next_index_string(param[0], *argv, 1);
 294                 argv++;
 295         }
 296 
 297         /* set the milter context for possible use in API functions */
 298         MG(ctx) = ctx;
 299         MG(state) = MLFI_ENVFROM;
 300         
 301         status = call_user_function(CG(function_table), NULL, &function_name, &retval, 1, param TSRMLS_CC);
 302 
 303         MG(state) = MLFI_NONE;
 304         zval_ptr_dtor(param);
 305         
 306         if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
 307                 return Z_LVAL(retval);
 308         }
 309 
 310         return SMFIS_CONTINUE;
 311 }
 312 /* }}} */
 313 
 314 /* envelope recipient filter */
 315 /* {{{ mlfi_envrcpt()
 316 */
 317 static sfsistat mlfi_envrcpt(SMFICTX *ctx, char **argv)
 318 {
 319         zval function_name, retval, *param[1];
 320         int status;
 321         TSRMLS_FETCH();
 322 
 323         /* call userland */
 324         INIT_ZVAL(function_name);
 325         
 326         ALLOC_ZVAL(param[0]);
 327         INIT_PZVAL(param[0]);
 328 
 329         ZVAL_STRING(&function_name, "milter_envrcpt", 0);
 330         array_init(param[0]);
 331 
 332         while (*argv) {
 333                 add_next_index_string(param[0], *argv, 1);
 334                 argv++;
 335         }
 336 
 337         /* set the milter context for possible use in API functions */
 338         MG(ctx) = ctx;
 339         MG(state) = MLFI_ENVRCPT;
 340         
 341         status = call_user_function(CG(function_table), NULL, &function_name, &retval, 1, param TSRMLS_CC);
 342 
 343         MG(state) = MLFI_NONE;
 344         
 345         zval_ptr_dtor(param);
 346         
 347         if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
 348                 return Z_LVAL(retval);
 349         }
 350 
 351         return SMFIS_CONTINUE;
 352 }
 353 /* }}} */
 354 
 355 /* header filter */
 356 /* {{{ mlfi_header()
 357 */
 358 static sfsistat mlfi_header(SMFICTX *ctx, char *headerf, char *headerv)
 359 {
 360         zval function_name, retval, *param[2];
 361         int status;
 362         TSRMLS_FETCH();
 363 
 364         /* call userland */
 365         INIT_ZVAL(function_name);
 366         
 367         ALLOC_ZVAL(param[0]);
 368         ALLOC_ZVAL(param[1]);
 369         INIT_PZVAL(param[0]);
 370         INIT_PZVAL(param[1]);
 371         
 372         ZVAL_STRING(&function_name, "milter_header", 0);
 373         ZVAL_STRING(param[0], headerf, 1);
 374         ZVAL_STRING(param[1], headerv, 1);
 375 
 376         /* set the milter context for possible use in API functions */
 377         MG(ctx) = ctx;
 378         MG(state) = MLFI_HEADER;
 379         
 380         status = call_user_function(CG(function_table), NULL, &function_name, &retval, 2, param TSRMLS_CC);
 381 
 382         MG(state) = MLFI_NONE;
 383         
 384         zval_ptr_dtor(&param[0]);
 385         zval_ptr_dtor(&param[1]);       
 386         
 387         if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
 388                 return Z_LVAL(retval);
 389         }
 390         
 391         return SMFIS_CONTINUE;
 392 }
 393 /* }}} */
 394 
 395 /* end of header */
 396 /* {{{ mlfi_eoh()
 397 */
 398 static sfsistat mlfi_eoh(SMFICTX *ctx)
 399 {
 400         zval function_name, retval;
 401         int status;
 402         TSRMLS_FETCH();
 403 
 404         /* call userland */
 405         INIT_ZVAL(function_name);
 406         ZVAL_STRING(&function_name, "milter_eoh", 0);
 407 
 408         /* set the milter context for possible use in API functions */
 409         MG(ctx) = ctx;
 410         MG(state) = MLFI_EOH;
 411         
 412         status = call_user_function(CG(function_table), NULL, &function_name, &retval, 0, NULL TSRMLS_CC);
 413 
 414         MG(state) = MLFI_NONE;
 415         
 416         if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
 417                 return Z_LVAL(retval);
 418         }
 419 
 420         return SMFIS_CONTINUE;
 421 }
 422 /* }}} */
 423 
 424 /* body block */
 425 /* {{{ mlfi_body()
 426 */
 427 static sfsistat mlfi_body(SMFICTX *ctx, u_char *bodyp, size_t len)
 428 {
 429         zval function_name, retval, *param[1];
 430         int status;
 431         TSRMLS_FETCH();
 432 
 433         /* call userland */
 434         INIT_ZVAL(function_name);
 435         
 436         ALLOC_ZVAL(param[0]);
 437         INIT_PZVAL(param[0]);
 438 
 439         ZVAL_STRING(&function_name, "milter_body", 0);
 440         ZVAL_STRINGL(param[0], (char*)bodyp, len, 1); /*alex*/
 441         
 442         /* set the milter context for possible use in API functions */
 443         MG(ctx) = ctx;
 444         MG(state) = MLFI_BODY;
 445         
 446         status = call_user_function(CG(function_table), NULL, &function_name, &retval, 1, param TSRMLS_CC);
 447 
 448         MG(state) = MLFI_NONE;
 449         
 450         zval_ptr_dtor(param);   
 451 
 452         if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
 453                 return Z_LVAL(retval);
 454         }
 455 
 456         return SMFIS_CONTINUE;
 457 }
 458 /* }}} */
 459 
 460 /* end of message */
 461 /* {{{ mlfi_eom()
 462 */
 463 static sfsistat mlfi_eom(SMFICTX *ctx)
 464 {
 465         zval function_name, retval;
 466         int status;
 467         TSRMLS_FETCH();
 468 
 469         /* call userland */
 470         INIT_ZVAL(function_name);
 471         ZVAL_STRING(&function_name, "milter_eom", 0);
 472         
 473         /* set the milter context for possible use in API functions */
 474         MG(ctx) = ctx;
 475         MG(state) = MLFI_EOM;
 476 
 477         status = call_user_function(CG(function_table), NULL, &function_name, &retval, 0, NULL TSRMLS_CC);
 478 
 479         MG(state) = MLFI_NONE;
 480         
 481         if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
 482                 return Z_LVAL(retval);
 483         }
 484 
 485         return SMFIS_CONTINUE;
 486 }
 487 /* }}} */
 488 
 489 /* message aborted */
 490 /* {{{ mlfi_abort()
 491 */
 492 static sfsistat mlfi_abort(SMFICTX *ctx)
 493 {
 494         zval function_name, retval;
 495         int status;
 496         TSRMLS_FETCH();
 497 
 498         /* call userland */
 499         INIT_ZVAL(function_name);
 500         ZVAL_STRING(&function_name, "milter_abort", 0);
 501         
 502         /* set the milter context for possible use in API functions */
 503         MG(ctx) = ctx;
 504         MG(state) = MLFI_ABORT;
 505         
 506         status = call_user_function(CG(function_table), NULL, &function_name, &retval, 0, NULL TSRMLS_CC);
 507 
 508         MG(state) = MLFI_NONE;
 509         
 510         if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
 511                 return Z_LVAL(retval);
 512         }
 513 
 514         return SMFIS_CONTINUE;
 515 }
 516 /* }}} */
 517 
 518 /* connection cleanup */
 519 /* {{{ mlfi_close()
 520 */
 521 static sfsistat mlfi_close(SMFICTX *ctx)
 522 {
 523         int ret = SMFIS_CONTINUE;
 524         zval function_name, retval;
 525         int status;
 526         TSRMLS_FETCH();
 527 
 528         if (!SG(sapi_started) && SUCCESS != php_request_startup(TSRMLS_C)) {
 529                 return ret;
 530         }
 531 
 532         /* call userland */
 533         INIT_ZVAL(function_name);
 534         ZVAL_STRING(&function_name, "milter_close", 0);
 535         
 536         /* set the milter context for possible use in API functions */
 537         MG(ctx) = ctx;
 538         MG(state) = MLFI_CLOSE;
 539         
 540         status = call_user_function(CG(function_table), NULL, &function_name, &retval, 0, NULL TSRMLS_CC);
 541 
 542         MG(state) = MLFI_NONE;
 543         
 544         if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
 545                 ret = Z_LVAL(retval);
 546         }
 547         
 548         php_request_shutdown((void *) 0);
 549 
 550         return ret;
 551 }
 552 /* }}} */
 553 /* }}} */
 554 
 555 /* {{{ Milter entry struct
 556  */
 557 static struct smfiDesc smfilter = {
 558     "php-milter",       /* filter name */
 559     SMFI_VERSION,   /* version code -- leave untouched */
 560     0,                          /* flags */
 561     mlfi_connect,       /* info filter callback */
 562     mlfi_helo,          /* HELO filter callback */
 563     mlfi_envfrom,       /* envelope filter callback */
 564     mlfi_envrcpt,       /* envelope recipient filter callback */
 565     mlfi_header,        /* header filter callback */
 566     mlfi_eoh,           /* end of header callback */
 567     mlfi_body,          /* body filter callback */
 568     mlfi_eom,           /* end of message callback */
 569     mlfi_abort,         /* message aborted callback */
 570     mlfi_close,         /* connection cleanup callback */
 571 };
 572 /* }}} */
 573 
 574 /* {{{ PHP Milter API
 575  */
 576 
 577 /* {{{ proto void smfi_setflags(long flags)
 578    Sets the flags describing the actions the filter may take. */        
 579 PHP_FUNCTION(smfi_setflags)
 580 {
 581         long flags;
 582         
 583         /* valid only in the init callback */
 584         if (MG(state) != MLFI_INIT) {
 585                 php_error(E_WARNING, NOT_INIT, get_active_function_name(TSRMLS_C));
 586         } else if (zend_parse_parameters(1 TSRMLS_CC, "l", &flags) == SUCCESS) {
 587                 flags = flags & (SMFIF_ADDHDRS|SMFIF_CHGHDRS|SMFIF_CHGBODY|SMFIF_ADDRCPT|SMFIF_DELRCPT);
 588                 smfilter.xxfi_flags = flags;
 589         }       
 590 }
 591 /* }}} */
 592 
 593 /* {{{ proto void smfi_settimeout(long timeout)
 594    Sets the number of seconds libmilter will wait for an MTA connection before timing out a socket. */  
 595 PHP_FUNCTION(smfi_settimeout)
 596 {
 597         long timeout;
 598         
 599         /* valid only in the init callback */
 600         if (MG(state) != MLFI_INIT) {
 601                 php_error(E_WARNING, NOT_INIT, get_active_function_name(TSRMLS_C));
 602         } else if (zend_parse_parameters(1 TSRMLS_CC, "l", &timeout) == SUCCESS) {
 603                 smfi_settimeout(timeout);
 604         }       
 605 }
 606 /* }}} */
 607 
 608 /* {{{ proto string smfi_getsymval(string macro)
 609    Returns the value of the given macro or NULL if the macro is not defined. */ 
 610 PHP_FUNCTION(smfi_getsymval)
 611 {
 612         char *symname, *ret;
 613         int len;
 614 
 615         /* valid in any callback */
 616         if (MG(state) == MLFI_NONE) {
 617                 php_error(E_WARNING, IS_NONE, get_active_function_name(TSRMLS_C));
 618         } else if (zend_parse_parameters(1 TSRMLS_CC, "s", &symname, &len) == SUCCESS) {
 619                 if ((ret = smfi_getsymval(MG(ctx), symname)) != NULL) {
 620                         RETURN_STRING(ret, 1);
 621                 }
 622         }
 623 
 624         RETURN_NULL();
 625 }
 626 /* }}} */
 627 
 628 /* {{{ proto bool smfi_setreply(string rcode, string xcode, string message)
 629    Directly set the SMTP error reply code for this connection.
 630    This code will be used on subsequent error replies resulting from actions taken by this filter. */   
 631 PHP_FUNCTION(smfi_setreply)
 632 {
 633         char *rcode, *xcode, *message;
 634         int len;
 635         
 636         /* valid in any callback */
 637         if (MG(state) == MLFI_NONE) {
 638                 php_error(E_WARNING, IS_NONE, get_active_function_name(TSRMLS_C));
 639         } else if (zend_parse_parameters(3 TSRMLS_CC, "sss", &rcode, &len, &xcode, &len, &message, &len) == SUCCESS) {
 640                 if (smfi_setreply(MG(ctx), rcode, xcode, message) == MI_SUCCESS) {
 641                         RETURN_TRUE;
 642                 }
 643         }
 644         
 645         RETURN_FALSE;
 646 }
 647 /* }}} */
 648 
 649 /* {{{ proto bool smfi_addheader(string headerf, string headerv)
 650    Adds a header to the current message. */     
 651 PHP_FUNCTION(smfi_addheader)
 652 {
 653         char *f, *v;
 654         int len;
 655         
 656         /* valid only in milter_eom */
 657         if (MG(state) != MLFI_EOM) {
 658                 php_error(E_WARNING, NOT_EOM, get_active_function_name(TSRMLS_C));
 659         } else if (zend_parse_parameters(2 TSRMLS_CC, "ss", &f, &len, &v, &len) == SUCCESS) {
 660                 if (smfi_addheader(MG(ctx), f, v) == MI_SUCCESS) {
 661                         RETURN_TRUE;
 662                 }
 663         }
 664         
 665         RETURN_FALSE;
 666 }
 667 /* }}} */
 668 
 669 /* {{{ proto bool smfi_chgheader(string headerf, string headerv)
 670    Changes a header's value for the current message. */ 
 671 PHP_FUNCTION(smfi_chgheader)
 672 {
 673         char *f, *v;
 674         long idx;
 675         int len;
 676         
 677         /* valid only in milter_eom */
 678         if (MG(state) != MLFI_EOM) {
 679                 php_error(E_WARNING, NOT_EOM, get_active_function_name(TSRMLS_C));
 680         } else if (zend_parse_parameters(3 TSRMLS_CC, "sls", &f, &len, &idx, &v, &len) == SUCCESS) {
 681                 if (smfi_chgheader(MG(ctx), f, idx, v) == MI_SUCCESS) {
 682                         RETURN_TRUE;
 683                 }
 684         }
 685         
 686         RETURN_FALSE;
 687 }
 688 /* }}} */
 689 
 690 /* {{{ proto bool smfi_addrcpt(string rcpt)
 691    Add a recipient to the message envelope. */  
 692 PHP_FUNCTION(smfi_addrcpt)
 693 {
 694         char *rcpt;
 695         int len;
 696         
 697         /* valid only in milter_eom */
 698         if (MG(state) != MLFI_EOM) {
 699                 php_error(E_WARNING, NOT_EOM, get_active_function_name(TSRMLS_C));
 700         } else if (zend_parse_parameters(1 TSRMLS_CC, "s", &rcpt, &len) == SUCCESS) {
 701                 if (smfi_addrcpt(MG(ctx), rcpt) == MI_SUCCESS) {
 702                         RETURN_TRUE;
 703                 }
 704         }
 705         
 706         RETURN_FALSE;
 707 }
 708 /* }}} */
 709 
 710 /* {{{ proto bool smfi_delrcpt(string rcpt)
 711    Removes the named recipient from the current message's envelope. */  
 712 PHP_FUNCTION(smfi_delrcpt)
 713 {
 714         char *rcpt;
 715         int len;
 716         
 717         /* valid only in milter_eom */
 718         if (MG(state) != MLFI_EOM) {
 719                 php_error(E_WARNING, NOT_EOM, get_active_function_name(TSRMLS_C));
 720         } else if (zend_parse_parameters(1 TSRMLS_CC, "s", &rcpt, &len) == SUCCESS) {
 721                 if (smfi_delrcpt(MG(ctx), rcpt) == MI_SUCCESS) {
 722                         RETURN_TRUE;
 723                 }
 724         }
 725         
 726         RETURN_FALSE;
 727 }
 728 /* }}} */
 729 
 730 /* {{{ proto bool smfi_replacebody(string body)
 731    Replaces the body of the current message. If called more than once,
 732    subsequent calls result in data being appended to the new body. */   
 733 PHP_FUNCTION(smfi_replacebody)
 734 {
 735         char *body;
 736         int len;
 737         
 738         /* valid only in milter_eom */
 739         if (MG(state) != MLFI_EOM) {
 740                 php_error(E_WARNING, NOT_EOM, get_active_function_name(TSRMLS_C));
 741         } else if (zend_parse_parameters(1 TSRMLS_CC, "s", &body, &len) == SUCCESS) {
 742                 if (smfi_replacebody(MG(ctx), (u_char*)body, len) == MI_SUCCESS) {
 743                         RETURN_TRUE;
 744                 }
 745         }
 746         
 747         RETURN_FALSE;
 748 }
 749 /* }}} */
 750 
 751 /* {{{ PHP_MINIT_FUNCTION
 752  */
 753 PHP_MINIT_FUNCTION(milter)
 754 {
 755         REGISTER_LONG_CONSTANT("SMFIS_CONTINUE",        SMFIS_CONTINUE, CONST_CS | CONST_PERSISTENT);
 756         REGISTER_LONG_CONSTANT("SMFIS_REJECT",          SMFIS_REJECT,   CONST_CS | CONST_PERSISTENT);
 757         REGISTER_LONG_CONSTANT("SMFIS_DISCARD",         SMFIS_DISCARD,  CONST_CS | CONST_PERSISTENT);
 758         REGISTER_LONG_CONSTANT("SMFIS_ACCEPT",          SMFIS_ACCEPT,   CONST_CS | CONST_PERSISTENT);
 759         REGISTER_LONG_CONSTANT("SMFIS_TEMPFAIL",        SMFIS_TEMPFAIL, CONST_CS | CONST_PERSISTENT);
 760 
 761         REGISTER_LONG_CONSTANT("SMFIF_ADDHDRS",         SMFIF_ADDHDRS,  CONST_CS | CONST_PERSISTENT);
 762         REGISTER_LONG_CONSTANT("SMFIF_CHGHDRS",         SMFIF_CHGHDRS,  CONST_CS | CONST_PERSISTENT);
 763         REGISTER_LONG_CONSTANT("SMFIF_CHGBODY",         SMFIF_CHGBODY,  CONST_CS | CONST_PERSISTENT);
 764         REGISTER_LONG_CONSTANT("SMFIF_ADDRCPT",         SMFIF_ADDRCPT,  CONST_CS | CONST_PERSISTENT);
 765         REGISTER_LONG_CONSTANT("SMFIF_DELRCPT",         SMFIF_DELRCPT,  CONST_CS | CONST_PERSISTENT);
 766 
 767         ZEND_INIT_MODULE_GLOBALS(milter, NULL, NULL);
 768 
 769         MG(state) = MLFI_NONE;
 770         MG(initialized) = 0;
 771         return SUCCESS;
 772 }
 773 /* }}} */
 774 
 775 /* {{{ PHP_MINFO_FUNCTION
 776  */
 777 PHP_MINFO_FUNCTION(milter)
 778 {
 779         php_info_print_table_start();
 780         php_info_print_table_header(2, "Milter support", "enabled");
 781         php_info_print_table_end();
 782 }
 783 /* }}} */
 784 /* }}} */
 785 
 786 /* {{{ arginfo */
 787 ZEND_BEGIN_ARG_INFO_EX(arginfo_smfi_setflags, 0, 0, 1)
 788         ZEND_ARG_INFO(0, flags)
 789 ZEND_END_ARG_INFO()
 790 
 791 ZEND_BEGIN_ARG_INFO_EX(arginfo_smfi_settimeout, 0, 0, 1)
 792         ZEND_ARG_INFO(0, timeout)
 793 ZEND_END_ARG_INFO()
 794 
 795 ZEND_BEGIN_ARG_INFO_EX(arginfo_smfi_getsymval, 0, 0, 1)
 796         ZEND_ARG_INFO(0, macro)
 797 ZEND_END_ARG_INFO()
 798 
 799 ZEND_BEGIN_ARG_INFO_EX(arginfo_smfi_setreply, 0, 0, 3)
 800         ZEND_ARG_INFO(0, rcode)
 801         ZEND_ARG_INFO(0, xcode)
 802         ZEND_ARG_INFO(0, message)
 803 ZEND_END_ARG_INFO()
 804 
 805 ZEND_BEGIN_ARG_INFO_EX(arginfo_smfi_addheader, 0, 0, 2)
 806         ZEND_ARG_INFO(0, headerf)
 807         ZEND_ARG_INFO(0, headerv)
 808 ZEND_END_ARG_INFO()
 809 
 810 ZEND_BEGIN_ARG_INFO_EX(arginfo_smfi_chgheader, 0, 0, 2)
 811         ZEND_ARG_INFO(0, headerf)
 812         ZEND_ARG_INFO(0, headerv)
 813 ZEND_END_ARG_INFO()
 814 
 815 ZEND_BEGIN_ARG_INFO_EX(arginfo_smfi_addrcpt, 0, 0, 1)
 816         ZEND_ARG_INFO(0, rcpt)
 817 ZEND_END_ARG_INFO()
 818 
 819 ZEND_BEGIN_ARG_INFO_EX(arginfo_smfi_delrcpt, 0, 0, 1)
 820         ZEND_ARG_INFO(0, rcpt)
 821 ZEND_END_ARG_INFO()
 822 
 823 ZEND_BEGIN_ARG_INFO_EX(arginfo_smfi_replacebody, 0, 0, 1)
 824         ZEND_ARG_INFO(0, body)
 825 ZEND_END_ARG_INFO()
 826 /* }}} */
 827 
 828 /* {{{ milter_functions[]
 829 */
 830 const static zend_function_entry milter_functions[] = {
 831         PHP_FE(smfi_setflags,           arginfo_smfi_setflags)
 832         PHP_FE(smfi_settimeout,         arginfo_smfi_settimeout)
 833         PHP_FE(smfi_getsymval,          arginfo_smfi_getsymval)
 834         PHP_FE(smfi_setreply,           arginfo_smfi_setreply)
 835         PHP_FE(smfi_addheader,          arginfo_smfi_addheader)
 836         PHP_FE(smfi_chgheader,          arginfo_smfi_chgheader)
 837         PHP_FE(smfi_addrcpt,            arginfo_smfi_addrcpt)
 838         PHP_FE(smfi_delrcpt,            arginfo_smfi_delrcpt)
 839         PHP_FE(smfi_replacebody,        arginfo_smfi_replacebody)
 840         PHP_FE_END
 841 };
 842 /* }}} */
 843 
 844 /* {{{ Zend module entry
 845 */
 846 static zend_module_entry php_milter_module = {
 847         STANDARD_MODULE_HEADER,
 848         "Milter",
 849         milter_functions,
 850         PHP_MINIT(milter),
 851         NULL,
 852         NULL,
 853         NULL,
 854         PHP_MINFO(milter),
 855         "0.1.0",
 856         STANDARD_MODULE_PROPERTIES
 857 };
 858 /* }}} */
 859 
 860 /* {{{ Milter SAPI
 861 */
 862 static int sapi_milter_ub_write(const char *str, uint str_length TSRMLS_DC)
 863 {
 864         return str_length;
 865 }
 866 
 867 static void sapi_milter_flush(void *server_context)
 868 {
 869 }
 870 
 871 static void sapi_milter_register_variables(zval *track_vars_array TSRMLS_DC)
 872 {
 873         php_register_variable ("SERVER_SOFTWARE", "Sendmail Milter", track_vars_array TSRMLS_CC);
 874 }
 875 
 876 static int sapi_milter_post_read(char *buf, uint count_bytes TSRMLS_DC)
 877 {
 878         return 0;
 879 }
 880 
 881 static char* sapi_milter_read_cookies(TSRMLS_D)
 882 {
 883         return NULL;
 884 }
 885 
 886 static int sapi_milter_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
 887 {
 888         return SAPI_HEADER_SENT_SUCCESSFULLY;
 889 }
 890 
 891 static int php_milter_startup(sapi_module_struct *sapi_module)
 892 {
 893         if (php_module_startup(sapi_module, &php_milter_module, 1) == FAILURE) {
 894                 return FAILURE;
 895         }
 896         return SUCCESS;
 897 }
 898 /* }}} */
 899 
 900 /* {{{ sapi_module_struct milter_sapi_module
 901 */
 902 static sapi_module_struct milter_sapi_module = {
 903         "milter",                                               /* name */
 904         "Sendmail Milter SAPI",                 /* pretty name */
 905 
 906         php_milter_startup,                             /* startup */
 907         php_module_shutdown_wrapper,    /* shutdown */
 908 
 909         NULL,                                                   /* activate */
 910         NULL,                                                   /* deactivate */
 911 
 912         sapi_milter_ub_write,                   /* unbuffered write */
 913         sapi_milter_flush,                              /* flush */
 914         NULL,                                                   /* get uid */
 915         NULL,                                                   /* getenv */
 916 
 917         php_error,                                              /* error handler */
 918 
 919         NULL,                                                   /* header handler */
 920         sapi_milter_send_headers,               /* send headers handler */
 921         NULL,                                                   /* send header handler */
 922 
 923         sapi_milter_post_read,                  /* read POST data */
 924         sapi_milter_read_cookies,               /* read Cookies */
 925 
 926         sapi_milter_register_variables, /* register server variables */
 927         NULL,                                                   /* Log message */
 928         NULL,                                                   /* Get request time */
 929         NULL,                                                   /* Child terminate */
 930 
 931         NULL,                                                   /* Block interruptions */
 932         NULL,                                                   /* Unblock interruptions */
 933 
 934         STANDARD_SAPI_MODULE_PROPERTIES
 935 };
 936 /* }}} */
 937 
 938 /****
 939 * ripped from cli, has to be cleaned up !
 940 */
 941 
 942 /* {{{ php_milter_usage
 943 */
 944 static void php_milter_usage(char *argv0)
 945 {
 946         char *prog;
 947 
 948         prog = strrchr(argv0, '/');
 949         if (prog) {
 950                 prog++;
 951         } else {
 952                 prog = "php-milter";
 953         }
 954 
 955         printf(     "Usage: %s [options] [-f] <file> [args...]\n"
 956                     "       %s [options] [-- args...]\n"
 957                                 "  -a               Run interactively\n"
 958                                 "  -c <path>|<file> Look for php.ini file in this directory\n"
 959                                 "  -n               No php.ini file will be used\n"
 960                                 "  -d foo[=bar]     Define INI entry foo with value 'bar'\n"
 961                                 "  -D               run as daemon\n"
 962                                 "  -e               Generate extended information for debugger/profiler\n"
 963                                 "  -f <file>        Parse <file>.\n"
 964                                 "  -h               This help\n"
 965                                 "  -p <socket>      path to create socket\n"
 966                                 "  -v               Version number\n"
 967                                 "  -V <n>           set debug level to n (1 or 2).\n"
 968                                 "  -z <file>        Load Zend extension <file>.\n"
 969                                 "  args...          Arguments passed to script. Use -- args when first argument \n"
 970                                 "                   starts with - or script is read from stdin\n"
 971                                 , prog, prog);
 972 }
 973 /* }}} */
 974 
 975 static void define_command_line_ini_entry(char *arg) /* {{{ */
 976 {
 977         char *name, *value;
 978 
 979         name = arg;
 980         value = strchr(arg, '=');
 981         if (value) {
 982                 *value = 0;
 983                 value++;
 984         } else {
 985                 value = "1";
 986         }
 987         zend_alter_ini_entry(name, strlen(name)+1, value, strlen(value), PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
 988 }
 989 /* }}} */
 990 
 991 /* {{{ main
 992 */
 993 int main(int argc, char *argv[])
 994 {
 995     char *sock = NULL;
 996         int dofork = 0;
 997 
 998         int exit_status = SUCCESS;
 999         int c;
1000 /* temporary locals */
1001         int orig_optind=ap_php_optind;
1002         char *orig_optarg=ap_php_optarg;
1003         int interactive=0;
1004         char *param_error=NULL;
1005 /* end of temporary locals */
1006 
1007         void ***tsrm_ls;
1008 
1009 #ifdef HAVE_SIGNAL_H
1010 #if defined(SIGPIPE) && defined(SIG_IGN)
1011         signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE in standalone mode so
1012                                                                 that sockets created via fsockopen()
1013                                                                 don't kill PHP if the remote site
1014                                                                 closes it.  in apache|apxs mode apache
1015                                                                 does that for us!  thies@thieso.net
1016                                                                 20000419 */
1017 #endif
1018 #endif
1019 
1020 
1021         tsrm_startup(1, 1, 0, NULL);
1022         tsrm_ls = ts_resource(0);
1023         sapi_startup(&milter_sapi_module);
1024         
1025         while ((c=ap_php_getopt(argc, argv, OPTSTRING))!=-1) {
1026                 switch (c) {
1027                 case 'c':
1028                         milter_sapi_module.php_ini_path_override = strdup(ap_php_optarg);
1029                         break;
1030                 case 'n':
1031                         milter_sapi_module.php_ini_ignore = 1;
1032                         break;
1033                 }
1034         }
1035         ap_php_optind = orig_optind;
1036         ap_php_optarg = orig_optarg;
1037 
1038         milter_sapi_module.executable_location = argv[0];
1039 
1040 
1041         sapi_module.startup(&milter_sapi_module);
1042 
1043         zend_first_try {
1044                 while ((c=ap_php_getopt(argc, argv, OPTSTRING))!=-1) {
1045                         switch (c) {
1046                         case '?':
1047                                 php_output_tearup();
1048                                 SG(headers_sent) = 1;
1049                                 php_milter_usage(argv[0]);
1050                                 php_output_teardown();
1051                                 exit(1);
1052                                 break;
1053                         }
1054                 }
1055                 ap_php_optind = orig_optind;
1056                 ap_php_optarg = orig_optarg;
1057 
1058         /* Set some CLI defaults */
1059                 SG(options) |= SAPI_OPTION_NO_CHDIR;
1060                 zend_alter_ini_entry("html_errors", 12, "0", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
1061                 zend_alter_ini_entry("max_execution_time", 19, "0", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
1062 
1063                 zend_uv.html_errors = 0; /* tell the engine we're in non-html mode */
1064 
1065                 while ((c = ap_php_getopt(argc, argv, OPTSTRING)) != -1) {
1066                         switch (c) {
1067 
1068                         case 'a':       /* interactive mode */
1069                                 printf("Interactive mode enabled\n\n");
1070                                 interactive=1;
1071                                 break;
1072 
1073                         case 'C': /* don't chdir to the script directory */
1074                                 /* This is default so NOP */
1075                                 break;
1076                         case 'd': /* define ini entries on command line */
1077                                 define_command_line_ini_entry(ap_php_optarg);
1078                                 break;
1079 
1080                         case 'D': /* daemon */
1081                                 dofork = 1;
1082                                 break;
1083 
1084                         case 'e': /* enable extended info output */
1085                                 CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO;
1086                                 break;
1087 
1088                         case 'f': /* parse file */
1089                                 filename = ap_php_optarg;
1090                                 break;
1091 
1092                         case 'h': /* help & quit */
1093                         case '?':
1094                                 php_output_tearup();
1095                                 SG(headers_sent) = 1;
1096                                 php_milter_usage(argv[0]);
1097                                 php_output_teardown();
1098                                 exit(1);
1099                                 break;
1100 
1101                         case 'p': /* socket */
1102                                 sock = strdup(ap_php_optarg);
1103                                 break;
1104 
1105                         case 'v': /* show php version & quit */
1106                                 if (php_request_startup(TSRMLS_C)==FAILURE) {
1107                                         zend_ini_deactivate(TSRMLS_C);
1108                                         php_module_shutdown(TSRMLS_C);
1109                                         sapi_shutdown();
1110                                         tsrm_shutdown();
1111 
1112                                         exit(1);
1113                                 }
1114                                 SG(headers_sent) = 1;
1115                                 SG(request_info).no_headers = 1;
1116                                 php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2016 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
1117                                 php_output_teardown();
1118                                 exit(1);
1119                                 break;
1120 
1121                         case 'V': /* verbose */
1122                                 flag_debug = atoi(ap_php_optarg);
1123                                 break;
1124 
1125                         case 'z': /* load extension file */
1126                                 zend_load_extension(ap_php_optarg);
1127                                 break;
1128 
1129                         default:
1130                                 break;
1131                         }
1132                 }
1133 
1134                 if (param_error) {
1135                         SG(headers_sent) = 1;
1136                         SG(request_info).no_headers = 1;
1137                         PUTS(param_error);
1138                         exit(1);
1139                 }
1140 
1141                 CG(interactive) = interactive;
1142 
1143                 /* only set script_file if not set already and not in direct mode and not at end of parameter list */
1144                 if (argc > ap_php_optind && !filename) {
1145                         filename=argv[ap_php_optind];
1146                         ap_php_optind++;
1147                 }
1148 
1149                 /* check if file exists, exit else */
1150                 
1151                 if (dofork) {
1152                         switch(fork()) {
1153                                 case -1: /* Uh-oh, we have a problem forking. */
1154                                         fprintf(stderr, "Uh-oh, couldn't fork!\n");
1155                                         exit(errno);
1156                                         break;
1157                                 case 0: /* Child */
1158                                         break;
1159                                 default: /* Parent */
1160                                         exit(0);
1161                         }
1162                 }
1163                         
1164                 if (sock) {
1165                         struct stat junk;
1166                         if (stat(sock,&junk) == 0) unlink(sock);
1167                 }
1168 
1169                 openlog("php-milter", LOG_PID, LOG_MAIL);
1170                 
1171                 if ((exit_status = mlfi_init())) {
1172                         syslog(1, "mlfi_init failed.");
1173                         closelog();
1174                         goto err;
1175                 }
1176 
1177                 smfi_setconn(sock);
1178                 if (smfi_register(smfilter) == MI_FAILURE) {
1179                         syslog(1, "smfi_register failed.");
1180                         fprintf(stderr, "smfi_register failed\n");
1181                         closelog();
1182                         goto err;
1183                 } else {
1184                         exit_status = smfi_main();
1185                 }                       
1186 
1187                 closelog();
1188 
1189                 if (milter_sapi_module.php_ini_path_override) {
1190                         free(milter_sapi_module.php_ini_path_override);
1191                 }
1192 
1193         } zend_catch {
1194                 exit_status = EG(exit_status);
1195         } zend_end_try();
1196 
1197 err:
1198         php_module_shutdown(TSRMLS_C);
1199         sapi_shutdown();
1200         tsrm_shutdown();
1201 
1202         exit(exit_status);
1203 }
1204 /* }}} */
1205 
1206 /*
1207  * Local variables:
1208  * tab-width: 4
1209  * c-basic-offset: 4
1210  * End:
1211  * vim600: sw=4 ts=4 fdm=marker
1212  * vim<600: sw=4 ts=4
1213  */

/* [<][>][^][v][top][bottom][index][help] */