X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/32dfdf8baa8ccf091a0d5d4d75e8627424898756..8ac90765750f87c573300b9e953af3d8090cab8b:/src/src/spool_in.c diff --git a/src/src/spool_in.c b/src/src/spool_in.c index a5b14959f..0b3490b22 100644 --- a/src/src/spool_in.c +++ b/src/src/spool_in.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2016 */ +/* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ /* Functions for reading spool files. When compiling for a utility (eximon), @@ -57,9 +57,17 @@ for (i = 0; i < 2; i++) fname = spool_fname(US"input", message_subdir, id, US"-D"); DEBUG(D_deliver) debug_printf("Trying spool file %s\n", fname); + /* We protect against symlink attacks both in not propagating the + * file-descriptor to other processes as we exec, and also ensuring that we + * don't even open symlinks. + * No -D file inside the spool area should be a symlink. + */ if ((fd = Uopen(fname, #ifdef O_CLOEXEC O_CLOEXEC | +#endif +#ifdef O_NOFOLLOW + O_NOFOLLOW | #endif O_RDWR | O_APPEND, 0)) >= 0) break; @@ -206,49 +214,13 @@ return TRUE; -/************************************************* -* Read spool header file * -*************************************************/ - -/* This function reads a spool header file and places the data into the -appropriate global variables. The header portion is always read, but header -structures are built only if read_headers is set true. It isn't, for example, -while generating -bp output. - -It may be possible for blocks of nulls (binary zeroes) to get written on the -end of a file if there is a system crash during writing. It was observed on an -earlier version of Exim that omitted to fsync() the files - this is thought to -have been the cause of that incident, but in any case, this code must be robust -against such an event, and if such a file is encountered, it must be treated as -malformed. - -As called from deliver_message() (at least) we are running as root. - -Arguments: - name name of the header file, including the -H - read_headers TRUE if in-store header structures are to be built - subdir_set TRUE is message_subdir is already set - -Returns: spool_read_OK success - spool_read_notopen open failed - spool_read_enverror error in the envelope portion - spool_read_hdrerror error in the header portion -*/ - -int -spool_read_header(uschar *name, BOOL read_headers, BOOL subdir_set) -{ -FILE *f = NULL; -int n; -int rcount = 0; -long int uid, gid; -BOOL inheader = FALSE; -uschar *p; - /* Reset all the global variables to their default values. However, there is one exception. DO NOT change the default value of dont_deliver, because it may be forced by an external setting. */ +void +spool_clear_header_globals(void) +{ acl_var_c = acl_var_m = NULL; authenticated_id = NULL; authenticated_sender = NULL; @@ -267,7 +239,9 @@ host_lookup_failed = FALSE; interface_address = NULL; interface_port = 0; local_error_message = FALSE; +#ifdef HAVE_LOCAL_SCAN local_scan_data = NULL; +#endif max_received_linelength = 0; message_linecount = 0; received_protocol = NULL; @@ -297,12 +271,12 @@ bmi_verdicts = NULL; #ifndef DISABLE_DKIM dkim_signers = NULL; dkim_disable_verify = FALSE; -dkim_collect_input = FALSE; +dkim_collect_input = 0; #endif #ifdef SUPPORT_TLS tls_in.certificate_verified = FALSE; -# ifdef EXPERIMENTAL_DANE +# ifdef SUPPORT_DANE tls_in.dane_verified = FALSE; # endif tls_in.cipher = NULL; @@ -313,6 +287,9 @@ tls_free_cert(&tls_in.peercert); tls_in.peerdn = NULL; tls_in.sni = NULL; tls_in.ocsp = OCSP_NOT_REQ; +# if defined(EXPERIMENTAL_REQUIRETLS) && !defined(COMPILE_UTILITY) +tls_requiretls = 0; +# endif #endif #ifdef WITH_CONTENT_SCAN @@ -328,6 +305,53 @@ message_utf8_downconvert = 0; dsn_ret = 0; dsn_envid = NULL; +} + + +/************************************************* +* Read spool header file * +*************************************************/ + +/* This function reads a spool header file and places the data into the +appropriate global variables. The header portion is always read, but header +structures are built only if read_headers is set true. It isn't, for example, +while generating -bp output. + +It may be possible for blocks of nulls (binary zeroes) to get written on the +end of a file if there is a system crash during writing. It was observed on an +earlier version of Exim that omitted to fsync() the files - this is thought to +have been the cause of that incident, but in any case, this code must be robust +against such an event, and if such a file is encountered, it must be treated as +malformed. + +As called from deliver_message() (at least) we are running as root. + +Arguments: + name name of the header file, including the -H + read_headers TRUE if in-store header structures are to be built + subdir_set TRUE is message_subdir is already set + +Returns: spool_read_OK success + spool_read_notopen open failed + spool_read_enverror error in the envelope portion + spool_read_hdrerror error in the header portion +*/ + +int +spool_read_header(uschar *name, BOOL read_headers, BOOL subdir_set) +{ +FILE *f = NULL; +int n; +int rcount = 0; +long int uid, gid; +BOOL inheader = FALSE; +uschar *p; + +/* Reset all the global variables to their default values. However, there is +one exception. DO NOT change the default value of dont_deliver, because it may +be forced by an external setting. */ + +spool_clear_header_globals(); /* Generate the full name and open the file. If message_subdir is already set, just look in the given directory. Otherwise, look in both the split @@ -459,8 +483,8 @@ for (;;) tree_node *node; endptr = Ustrchr(big_buffer + 6, ' '); if (endptr == NULL) goto SPOOL_FORMAT_ERROR; - name = string_sprintf("%c%.*s", big_buffer[4], endptr - big_buffer - 6, - big_buffer + 6); + name = string_sprintf("%c%.*s", big_buffer[4], + (int)(endptr - big_buffer - 6), big_buffer + 6); if (sscanf(CS endptr, " %d", &count) != 1) goto SPOOL_FORMAT_ERROR; node = acl_var_create(name); node->data.ptr = store_get(count + 1); @@ -578,8 +602,10 @@ for (;;) sender_local = TRUE; else if (Ustrcmp(big_buffer, "-localerror") == 0) local_error_message = TRUE; +#ifdef HAVE_LOCAL_SCAN else if (Ustrncmp(p, "ocal_scan ", 10) == 0) local_scan_data = string_copy(big_buffer + 12); +#endif break; case 'm': @@ -626,22 +652,30 @@ for (;;) #ifdef SUPPORT_TLS case 't': - if (Ustrncmp(p, "ls_certificate_verified", 23) == 0) - tls_in.certificate_verified = TRUE; - else if (Ustrncmp(p, "ls_cipher", 9) == 0) - tls_in.cipher = string_copy(big_buffer + 12); + if (Ustrncmp(p, "ls_", 3) == 0) + { + uschar * q = p + 3; + if (Ustrncmp(q, "certificate_verified", 20) == 0) + tls_in.certificate_verified = TRUE; + else if (Ustrncmp(q, "cipher", 6) == 0) + tls_in.cipher = string_copy(big_buffer + 12); # ifndef COMPILE_UTILITY /* tls support fns not built in */ - else if (Ustrncmp(p, "ls_ourcert", 10) == 0) - (void) tls_import_cert(big_buffer + 13, &tls_in.ourcert); - else if (Ustrncmp(p, "ls_peercert", 11) == 0) - (void) tls_import_cert(big_buffer + 14, &tls_in.peercert); + else if (Ustrncmp(q, "ourcert", 7) == 0) + (void) tls_import_cert(big_buffer + 13, &tls_in.ourcert); + else if (Ustrncmp(q, "peercert", 8) == 0) + (void) tls_import_cert(big_buffer + 14, &tls_in.peercert); # endif - else if (Ustrncmp(p, "ls_peerdn", 9) == 0) - tls_in.peerdn = string_unprinting(string_copy(big_buffer + 12)); - else if (Ustrncmp(p, "ls_sni", 6) == 0) - tls_in.sni = string_unprinting(string_copy(big_buffer + 9)); - else if (Ustrncmp(p, "ls_ocsp", 7) == 0) - tls_in.ocsp = big_buffer[10] - '0'; + else if (Ustrncmp(q, "peerdn", 6) == 0) + tls_in.peerdn = string_unprinting(string_copy(big_buffer + 12)); + else if (Ustrncmp(q, "sni", 3) == 0) + tls_in.sni = string_unprinting(string_copy(big_buffer + 9)); + else if (Ustrncmp(q, "ocsp", 4) == 0) + tls_in.ocsp = big_buffer[10] - '0'; +# if defined(EXPERIMENTAL_REQUIRETLS) && !defined(COMPILE_UTILITY) + else if (Ustrncmp(q, "requiretls", 10) == 0) + tls_requiretls = strtol(CS big_buffer+16, NULL, 0); +# endif + } break; #endif