// // based on source code from http://www.ols.es/exim/dlext/ by David Saez , // and local_scan.c from Yandex spamoborona http://so.yandex.ru // // warn set acl_m0 = ${dlfunc{/usr/local/libexec/exim/exim-dlfunc.so}{spamoborona2}\ // {/var/run/sp-daemon.sock}{defer_ok}} // // warn set acl_m0 = ${dlfunc{/usr/local/libexec/exim/exim-dlfunc.so}{spamoborona2}\ // {127.0.0.1 2525}{defer_ok}} // // warn set acl_m0 = ${dlfunc{/usr/local/libexec/exim/exim-dlfunc.so}{spamoborona2}\ // {213.180.204.68 2525}{defer_ok}{use_zlib}} // #define WITH_EXPERIMENTAL_REMOVE_HEADER #define WITH_ZLIB //#include "local_scan.h" //#include "macros.h" #include "exim.h" #include #include #include #include #include #include #include #include #ifdef WITH_ZLIB #include #endif //#define SO_TIMEOUT 120 #define READ_FAIL(x) ((x) < 0) #define MAX_SIZE_SO 64 * 1024 #define Z_SUFFIX 80 #define SO_FAILURE_HDR "X-SO-Flag" #define ERR_WRITE 53 #define ERR_READ 54 #define MAX_TMP_CREATE_FAILS 10 #define MAX_CONNECT_FAILS 32 extern uschar *tod_stamp(int); //extern BOOL split_spool_directory; /* TRUE to use multiple subdirs */ //extern uschar *spool_directory; /* Name of spool directory */ //extern uschar message_subdir[]; /* Subdirectory for messages */ const char temp_dir[] = "/var/spool/spamooborona"; //------------------------------------------------------------------------- int FakeSMTPCommand (int sock, char *command, char *value) { char sCommand[1024]; char answ [3]; int Len; sprintf(sCommand, "%s %s", command, value); debug_printf("Send to socket >> %s\n", sCommand); if (send(sock, sCommand, strlen(sCommand), 0) != (int)strlen(sCommand)) { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: socket sending '%s' error %d", sCommand, errno); // *yield = string_sprintf("so dlfunc: DEFER: socket sending '%s' error %d", sCommand, errno); return ERR_WRITE; } memset(answ, '\0', sizeof (answ)); Len = read(sock, answ, sizeof(answ)); if (READ_FAIL(Len)) { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: read() error %d, len=%d", errno, Len); // *yield = string_sprintf("so dlfunc: DEFER: read() error %d, len=%d", errno, Len); return ERR_WRITE; } debug_printf("Read from socket << %s\n", answ); if (strncmp (answ, "OK", 2) != 0) { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: server did not confirm, answ=%s", answ); // *yield = string_sprintf("so dlfunc: DEFER: server did not confirm, answ=%s", answ); return ERR_WRITE; // Cannot read message error code } return OK; } //------------------------------------------------------------------------- char *read_response(FILE *daemon_file, char *daemon_buffer, int daemon_buffer_size, int timeout) { char *rc; int save_errno; daemon_buffer[0] = 0; // In case nothing gets read sigalrm_seen = FALSE; alarm(timeout); rc = Ufgets(daemon_buffer, daemon_buffer_size, daemon_file); save_errno = errno; alarm(0); errno = save_errno; return(rc); } //------------------------------------------------------------------------- int spamoborona2(uschar **yield, int argc, uschar *argv[]) { char *arg_socket_addr; char *arg_defer_ok; int defer_ok; #ifdef WITH_ZLIB char *arg_use_zlib; int use_zlib; uschar so_buffer_compressed[MAX_SIZE_SO + Z_SUFFIX + 1]; #endif int so_sock = 0; FILE *so_file = NULL; char mbox_path[512]; int mbox_created = 0; int mbox_file = -1; FILE *spool_file = NULL; char spool_path[512]; static int miRand = 1; uschar *s; header_line *my_header, *header_new, *header_last, *tmp_headerlist; header_line *last_received = NULL; uschar *str; uschar so_buffer[MAX_SIZE_SO + 1]; uschar *address; int i, rejected; char RejectStr[4096]; int ccnt; int offset, read_count, wrote_count; unsigned long spool_file_size; char tcp_addr[128]; int tcp_port; struct hostent *he; struct in_addr in; struct sockaddr_un server; arg_socket_addr = argv[0]; arg_defer_ok = argv[1]; if (argc < 2) { defer_ok = 0; } else if ( (strcmpic(arg_defer_ok,US"1") == 0) || (strcmpic(arg_defer_ok,US"yes") == 0) || (strcmpic(arg_defer_ok,US"true") == 0) || (strcmpic(arg_defer_ok,US"defer_ok") == 0) ) { defer_ok = 1; } else { defer_ok = 0; } debug_printf(" defer_ok: %d\n", defer_ok); #ifdef WITH_ZLIB arg_use_zlib = argv[2]; if (argc < 3) { use_zlib = 0; } else if ( (strcmpic(arg_use_zlib,US"1") == 0) || (strcmpic(arg_use_zlib,US"yes") == 0) || (strcmpic(arg_use_zlib,US"true") == 0) || (strcmpic(arg_use_zlib,US"use_zlib") == 0) ) { use_zlib = 1; } else { use_zlib = 0; } debug_printf(" use_zlib: %d\n", use_zlib); #endif if (argc < 1) { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: Bad number of arguments: %d", argc); *yield = string_sprintf("so dlfunc: DEFER: Bad number of arguments: %d", argc); goto RETURN_DEFER; } if ((arg_socket_addr == NULL) || (arg_socket_addr[0] == 0)) { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: Socket address expected"); *yield = string_sprintf("so dlfunc: DEFER: Socket address expected"); goto RETURN_DEFER; } // // get message body stream // if (split_spool_directory == 0) { sprintf(spool_path, "%s/input/%s-D", spool_directory, message_id); } else { sprintf(spool_path, "%s/input/%s/%s-D", spool_directory, message_subdir, message_id); } debug_printf("Open spool file: %s\n", spool_path); spool_file = fopen(spool_path, "rb"); if (!spool_file) { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: Unable to spool message"); *yield = string_copy((uschar *)"so dlfunc: DEFER: Unable to spool message"); return(defer_ok ? OK : ERROR); } (void)fseek(spool_file, 0, SEEK_END); spool_file_size = ftell(spool_file); debug_printf(" Total spool file size: %d\n", spool_file_size); spool_file_size -= SPOOL_DATA_START_OFFSET; debug_printf(" Spool file size: %d\n", spool_file_size); debug_printf("fseek %d, %d\n", SPOOL_DATA_START_OFFSET, SEEK_SET); (void)fseek(spool_file, SPOOL_DATA_START_OFFSET, SEEK_SET); // // create socket // if (arg_socket_addr[0] == '/') { if ((so_sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: Unable to acquire socket (%s)", strerror(errno)); *yield = string_sprintf("so dlfunc: DEFER: Unable to acquire socket (%s)", strerror(errno)); goto RETURN_DEFER; } memset(&server, '\0', sizeof (struct sockaddr_un)); server.sun_family = AF_UNIX; if (Ustrlen(arg_socket_addr) > sizeof(server.sun_path) -1) { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: UNIX socket name %s too long", arg_socket_addr); *yield = string_sprintf("so dlfunc: DEFER: UNIX socket name %s too long", arg_socket_addr); goto RETURN_DEFER; } Ustrcpy(server.sun_path, arg_socket_addr); debug_printf("Use UNIX Domain socket %s\n", arg_socket_addr); } else { // if (arg_socket_addr[0] == '/') {} if (sscanf(CS arg_socket_addr, "%s %u", tcp_addr, &tcp_port) != 2 ) { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: Invalid so address: '%s'", arg_socket_addr); *yield = string_sprintf("so dlfunc: Invalid so address: '%s'", arg_socket_addr); goto RETURN_DEFER; } // Lookup the host if((he = gethostbyname(CS tcp_addr)) == 0) { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: failed to lookup host '%s'", tcp_addr); *yield = string_sprintf("so dlfunc: failed to lookup host '%s'", tcp_addr); goto RETURN_DEFER; } in = *(struct in_addr *) he->h_addr_list[0]; if ((so_sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: TCP socket creation failed: %s", strerror(errno)); *yield = string_sprintf("so dlfunc: TCP socket creation failed: %s", strerror(errno)); goto RETURN_DEFER; }; debug_printf("Use TCP socket %s:%d\n", tcp_addr, tcp_port); } // if (arg_socket_addr[0] == '/') {} // // connect to socket // i = MAX_CONNECT_FAILS; while (i > 0) { if (arg_socket_addr[0] == '/') { if (connect(so_sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { if (i > 1) { usleep(1000); } else { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: Unable to connect to UNIX socket %s (%s)", arg_socket_addr, strerror(errno)); *yield = string_sprintf("so dlfunc: DEFER: Unable to connect to UNIX socket %s (%s)", arg_socket_addr, strerror(errno)); goto RETURN_DEFER; } } else { break; } } else { if (ip_connect(so_sock, AF_INET, (uschar*)inet_ntoa(in), tcp_port, 5) < 0) { if (i > 1) { usleep(1000); } else { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: Unable to connect to TCP socket %s (%s)", socket, strerror(errno)); *yield = string_sprintf("so dlfunc: DEFER: Unable to connect to TCP socket %s (%s)", socket, strerror(errno)); goto RETURN_DEFER; } } else { break; } } i--; } so_file = fdopen(so_sock, "rb"); // // send envelope information to socket // // sender IP and hostname if (FakeSMTPCommand(so_sock, "CONNECT", (char *)expand_string(US"${sender_host_name} [${sender_host_address}]")) != OK) goto WRITE_FAILED; // envelope from address = expand_string(US"${sender_address}"); if (FakeSMTPCommand(so_sock, "MAILFROM", ((address == NULL) || (strlen(address) == 0)) ? "MAILER-DAEMON" : (char *)address) != OK) goto WRITE_FAILED; if ((argc >= 3) && (argv[3] != NULL) && (strlen(argv[3]) > 0)) { if (FakeSMTPCommand(so_sock, "RCPTTO", argv[3]) != OK) goto WRITE_FAILED; } else { // envelope to for (i = 0; i < recipients_count; i++) { if (FakeSMTPCommand(so_sock, "RCPTTO", recipients_list[i].address) != OK) goto WRITE_FAILED; } } // // prepare message headers // memset(&so_buffer, '\0', sizeof(so_buffer)); address = expand_string(US"${sender_address}"); if (address && *address) { s = string_sprintf("Return-path: <%s>\n", address); debug_printf("Write to temporary buffer: %s", s); Ustrcpy(so_buffer + Ustrlen(so_buffer), s); } // address = expand_string(US"${if def:received_for{$received_for}}"); address = expand_string(US"${received_for}"); if (!address || !*address) address = expand_string(US"${recipients}"); if (!address || !*address) address = expand_string(US"${local_part}@${domain}"); if (address && *address) { s = string_sprintf("Envelope-To: %s\n", address); debug_printf("Write to temporary buffer: %s", s); Ustrcpy(so_buffer + Ustrlen(so_buffer), s); } s = string_sprintf("Delivery-date: %s\n", tod_stamp(tod_full)); debug_printf("Write to temporary buffer: %s", s); Ustrcpy(so_buffer + Ustrlen(so_buffer), s); // create a copy of original headers list tmp_headerlist = NULL; header_last = NULL; for (my_header = header_list; my_header; my_header = my_header->next) { if ((my_header->type != '*') && (my_header->type != htype_old)) { header_new = store_get(sizeof(header_line)); header_new->text = string_copyn(my_header->text, my_header->slen); header_new->slen = my_header->slen; header_new->type = my_header->type; header_new->next = NULL; //debug_printf(" create a copy of header item: '%s'\n", header_new->text); if (tmp_headerlist == NULL) tmp_headerlist = header_new; if (header_last != NULL) header_last->next = header_new; header_last = header_new; } } #ifdef WITH_EXPERIMENTAL_REMOVE_HEADER // headers removed by acl_check_data if (acl_removed_headers != NULL) { for (my_header = tmp_headerlist; my_header != NULL; my_header = my_header->next) { uschar *list; list = acl_removed_headers; int sep = ':'; // This is specified as a colon-separated list uschar buffer[128]; while ((str = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) { int len = Ustrlen(str); if (header_testname(my_header, str, len, FALSE)) { //debug_printf(" header removed by acl_check_data: '%s'; '%s'\n", s, my_header->text); my_header->type = htype_old; } } } } #endif // headers added by acl_check_data my_header = acl_added_headers; while (my_header != NULL) { //debug_printf(" header added by acl_check_data: '%s'\n", my_header->text); header_new = store_get(sizeof(header_line)); header_new->text = string_copyn(my_header->text, my_header->slen); header_new->slen = my_header->slen; switch(my_header->type) { case htype_add_top: // add header at top header_new->next = tmp_headerlist; tmp_headerlist = header_new; break; case htype_add_rec: // add header after Received: if (last_received == NULL) { last_received = tmp_headerlist; while (!header_testname(last_received, US"Received", 8, FALSE)) last_received = last_received->next; while (last_received->next != NULL && header_testname(last_received->next, US"Received", 8, FALSE)) last_received = last_received->next; } header_new->next = last_received->next; last_received->next = header_new; break; case htype_add_rfc: // add header before any header which is NOT Received: or Resent- last_received = tmp_headerlist; while ( (last_received->next != NULL) && ( (header_testname(last_received->next, US"Received", 8, FALSE)) || (header_testname_incomplete(last_received->next, US"Resent-", 7, FALSE)) ) ) last_received = last_received->next; // last_received now points to the last Received: or Resent-* header // in an uninterrupted chain of those header types (seen from the beginning // of all headers. Our current header must follow it. header_new->next = last_received->next; last_received->next = header_new; break; default: // htype_add_bot // add header at bottom header_new->next = NULL; header_last->next = header_new; break; } if (header_new->next == NULL) header_last = header_new; my_header = my_header->next; } // copy headers to buffer for (my_header = tmp_headerlist; my_header; my_header = my_header->next) { if (my_header->type != '*') { if (Ustrlen(so_buffer) + my_header->slen >= sizeof(so_buffer)) { debug_printf("Headers tii long\n"); log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: Headers too long"); *yield = string_sprintf("so dlfunc: DEFER: Headers too long"); goto RETURN_DEFER; } debug_printf("Write to temporary buffer: %s", my_header->text); Ustrcpy(so_buffer + Ustrlen(so_buffer), my_header->text); } } s = string_sprintf("\r\n"); debug_printf("Write to temporary buffer: %s", s); if (Ustrlen(so_buffer) + Ustrlen(s) >= sizeof(so_buffer)) { debug_printf("Headers too long\n"); log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: Headers too long"); *yield = string_sprintf("so dlfunc: DEFER: Headers too long"); goto RETURN_DEFER; } Ustrcpy(so_buffer + Ustrlen(so_buffer), s); debug_printf("Headers wrote to temporary buffer\n"); // // Write message headers to temporary file or socket // if (arg_socket_addr[0] == '/') { // // create temporary file // for (i = 0; i < MAX_TMP_CREATE_FAILS; i++) { sprintf(mbox_path, "%s/%s-%8.8d-%3.3d-%6.6d", temp_dir, message_id, getpid(), miRand++, time(NULL)); umask ((mode_t) 0); debug_printf("Create temporary file %s\n", mbox_path); if ((mbox_file = open(mbox_path, O_RDWR | O_EXCL | O_CREAT, 0640)) > 0) break; if (errno != EEXIST) { // Unexpected error debug_printf("Unable create temporary file: %d\n", errno); log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: Unable create temporary file %s: %d", mbox_path, errno); *yield = string_sprintf("so dlfunc: DEFER: Unable create temporary file %s: %d", mbox_path, errno); goto RETURN_DEFER; } // Else, for some reason this file exists. Try again after a short sleep sleep(1); } if (mbox_file <= 0) { debug_printf("Unable create temporary file\n"); log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: Unable create temporary file %s", mbox_path); *yield = string_sprintf("so dlfunc: DEFER: Unable create temporary file %s", mbox_path); goto RETURN_DEFER; } if (strlen(so_buffer) > 0) { debug_printf("Write to temporary file: %s", so_buffer); if (write(mbox_file, so_buffer, strlen(so_buffer)) != strlen(so_buffer)) goto FILE_WRITE_FAILED; } } else { // if (arg_socket_addr[0] == '/') { } char size_str[12]; #ifdef WITH_ZLIB if (use_zlib) { int headers_size, so_buffer_compressed_size; headers_size = strlen(so_buffer); read_count = fread(so_buffer + headers_size, 1, sizeof(so_buffer) - 1 - headers_size, spool_file); so_buffer[headers_size + read_count] = 0; so_buffer_compressed_size = sizeof(so_buffer_compressed); if (compress((Bytef *)&so_buffer_compressed, &so_buffer_compressed_size, (Bytef *)&so_buffer, headers_size + read_count) != Z_OK) { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: compression error"); // *yield = string_sprintf("so dlfunc: DEFER: compression error"); goto WRITE_FAILED; } sprintf(size_str, "SIZE=%d", so_buffer_compressed_size); if (FakeSMTPCommand(so_sock, "DATA", size_str) != OK) goto WRITE_FAILED; debug_printf("Send %d bytes of compressed message to socket\n", so_buffer_compressed_size); if (send(so_sock, so_buffer_compressed, so_buffer_compressed_size, 0) != (int)so_buffer_compressed_size) { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: socket sending compressed headers and body error %d", errno); // *yield = string_sprintf("so dlfunc: DEFER: socket sending compressed headers and body error %d", errno); goto WRITE_FAILED; } (void)fseek(spool_file, 0, SEEK_END); } else { #endif sprintf(size_str, "SIZE=%d", strlen(so_buffer) + spool_file_size); if (FakeSMTPCommand(so_sock, "DATA", size_str) != OK) goto WRITE_FAILED; debug_printf("Send to socket >> %s\n", so_buffer); if (send(so_sock, so_buffer, strlen(so_buffer), 0) != (int)strlen(so_buffer)) { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: socket sending headers error %d", errno); // *yield = string_sprintf("so dlfunc: DEFER: socket sending headers error %d", errno); goto WRITE_FAILED; } #ifdef WITH_ZLIB } #endif } // if (arg_socket_addr[0] == '/') { } // // Write message body to temporary file or socket // do { read_count = fread(so_buffer, 1, sizeof(so_buffer) - 1, spool_file); so_buffer[read_count] = 0; //debug_printf("Read %d bytes from file: %s", read_count, so_buffer); debug_printf("Read %d bytes from spool file\n", read_count); if (read_count > 0) { if (arg_socket_addr[0] == '/') { offset = 0; //debug_printf("Write %d bytes to temporary file\n", wrote_count, so_buffer); again: wrote_count = write(mbox_file, so_buffer + offset, read_count - offset); debug_printf("Wrote %d bytes to temporary file\n", wrote_count); if (wrote_count == -1) goto FILE_WRITE_FAILED; if (offset + wrote_count < read_count) { offset += wrote_count; goto again; } } else { // if (arg_socket_addr[0] == '/') {} debug_printf("Send to socket %d bytes of message body\n", strlen(so_buffer)); if (send(so_sock, so_buffer, strlen(so_buffer), 0) != (int)strlen(so_buffer)) { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: socket body sending error %d", errno); // *yield = string_sprintf("so dlfunc: DEFER: socket body sending error %d", errno); goto WRITE_FAILED; } } // if (arg_socket_addr[0] == '/') {} } } while (!feof(spool_file) && !ferror(spool_file)); if (ferror(spool_file)) { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: error reading spool file: %s", strerror(errno)); *yield = string_sprintf("so dlfunc: error reading spool file: %s", strerror(errno)); goto RETURN_DEFER; } debug_printf("Close spool file: %s\n", spool_path); (void)fclose(spool_file); spool_file = NULL; // // Save temporary file end send it's name to socket // if (arg_socket_addr[0] == '/') { debug_printf("Save temporary file: %s\n", mbox_path); (void)close(mbox_file); mbox_file = -1; mbox_created = 1; if (FakeSMTPCommand(so_sock, "DATA", mbox_path) != OK) goto WRITE_FAILED; if (FakeSMTPCommand(so_sock, ".", "") != OK) goto WRITE_FAILED; } // if (arg_socket_addr[0] == '/') {} // // Read answer from socket // memset(so_buffer, '\0', sizeof(so_buffer)); { int Len; int answer_size; char answ[4096]; char *strP, *tok, *tmp, *tmp2; memset(RejectStr, '\0', sizeof(RejectStr)); Len = read(so_sock, answ, sizeof(answ) - 1); debug_printf("Read from socket: '%s'\n", answ); if (strncmp(answ, "SODAEMON ", 9) == 0) { strP = (char *)answ; for (tok = (char *)strtok (strP, "\n"); tok; tok = (char *)strtok (NULL, "\n")) { // signature always goes first if (strncmp (tok, "SODAEMON ", 9) == 0) { if (sscanf (tok, "%*s %d", &answer_size) == 1) { if (answer_size == 0) { // empty reply debug_printf("Zero answer size, check skiped\n"); Ustrcpy(so_buffer + Ustrlen(so_buffer), SO_FAILURE_HDR); Ustrcpy(so_buffer + Ustrlen(so_buffer), ": SKIP\n"); goto RETURN_OK; } else { if (answer_size + strlen(tok) + 1 > sizeof (answ) - 1) { debug_printf("daemon answer too long (%d bytes)\n", answer_size); log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: daemon answer too long (%d bytes)", answer_size); *yield = string_sprintf("so dlfunc: DEFER: daemon answer too long (%d bytes)", answer_size); goto RETURN_DEFER; } answ[strlen(tok) + 1 + answer_size] = 0; } } continue; } // reject or accept flag if (strncmp (tok, "REJECT ", 7) == 0) { sscanf (tok, "%*s %d", &rejected); continue; } // reject string if (strncmp (tok, "REJECTSTR ", 10) == 0) { if (rejected) { tmp = strchr(tok, ' '); tmp2 = tmp; if ((tmp2 != NULL) && (tmp2[0] == ' ')) tmp2++; if ((tmp2 == NULL) || (Ustrlen(tmp2) == 0)) { Ustrcpy(RejectStr, "Spam message rejected"); } else { Ustrcpy(RejectStr, tmp2); } } continue; } // spam flag if (strncmp (tok, "SPAM ", 5) == 0) { continue; } // spam label if (strncmp (tok, "SPAMSTR ", 8) == 0) { continue; } Ustrcpy(so_buffer + Ustrlen(so_buffer), tok); Ustrcpy(so_buffer + Ustrlen(so_buffer), "\n"); } } else { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: wrong signature in answer: %s", answ); *yield = string_sprintf("so dlfunc: DEFER: wrong signature in answer: %s", answ); goto RETURN_DEFER; } } goto RETURN_OK; FILE_WRITE_FAILED: { log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: Unable to write to temporary file %s", mbox_path); *yield = string_sprintf("so dlfunc: DEFER: Unable to write to temporary file %s", mbox_path); goto RETURN_DEFER; } WRITE_FAILED: { // log_write(0, LOG_MAIN|LOG_PANIC, // "so dlfunc: %s on so socket", strerror(errno)); *yield = string_sprintf("so dlfunc: DEFER: %s on so socket", strerror(errno)); goto RETURN_DEFER; } RESPONSE_FAILED: { int code; int save_errno; int more_errno; uschar message_buffer[256]; uschar *message; save_errno = errno; message = &message_buffer[0]; log_write(0, LOG_MAIN|LOG_PANIC, "so dlfunc: %s", message); *yield = string_sprintf("so dlfunc: DEFER: %s", message); goto RETURN_DEFER; } RETURN_DEFER: { if (so_file > 0) (void)fclose(so_file); if (so_sock > 0) (void)close(so_sock); if (spool_file > 0) (void)fclose(spool_file); if (mbox_file > 0) { (void)close(mbox_file); mbox_file = -1; } if (mbox_created > 0) { debug_printf("Remove temporary file %s\n", mbox_path); unlink(mbox_path); mbox_created = 0; } if ((*yield == NULL) || (*yield[0] == '\0')) *yield = string_sprintf("so dlfunc: DEFER"); return(defer_ok ? OK : ERROR); } RETURN_OK: { if (so_file > 0) (void)fclose(so_file); if (so_sock > 0) (void)close(so_sock); if (spool_file > 0) (void)fclose(spool_file); if (mbox_file > 0) { (void)close(mbox_file); mbox_file = -1; } if (mbox_created > 0) { debug_printf("Remove temporary file %s\n", mbox_path); unlink(mbox_path); mbox_created = 0; } if (rejected) { *yield = string_sprintf("so dlfunc: REJECT: %s\n%s", RejectStr, so_buffer); } else { *yield = string_sprintf("so dlfunc: ACCEPT\n%s", so_buffer); } // if ((*yield == NULL) || (*yield[0] == '\0')) // *yield = string_sprintf("so dlfunc: ACCEPT"); return OK; } return OK; }