Avoid modifying global errno when raising event
[exim.git] / src / src / functions.h
index 5ffb23d1e0cced19d0b503a754c1913eadc747e1..34a6fb7862daec4c880079f348f72def525de019 100644 (file)
@@ -3,7 +3,7 @@
 *************************************************/
 
 /* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim Maintainers 2020 */
+/* Copyright (c) The Exim Maintainers 2020 - 2021 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 
@@ -56,9 +56,9 @@ extern BOOL    tls_client_start(client_conn_ctx *, smtp_connect_args *,
 extern void    tls_client_creds_reload(BOOL);
 
 extern void    tls_close(void *, int);
-extern BOOL    tls_could_read(void);
+extern BOOL    tls_could_getc(void);
 extern void    tls_daemon_init(void);
-extern void    tls_daemon_tick(void);
+extern int     tls_daemon_tick(void);
 extern BOOL    tls_dropprivs_validate_require_cipher(BOOL);
 extern BOOL    tls_export_cert(uschar *, size_t, void *);
 extern int     tls_feof(void);
@@ -67,7 +67,8 @@ extern uschar *tls_field_from_dn(uschar *, const uschar *);
 extern void    tls_free_cert(void **);
 extern int     tls_getc(unsigned);
 extern uschar *tls_getbuf(unsigned *);
-extern void    tls_get_cache(void);
+extern void    tls_get_cache(unsigned);
+extern BOOL    tls_hasc(void);
 extern BOOL    tls_import_cert(const uschar *, void **);
 extern BOOL    tls_is_name_for_cert(const uschar *, void *);
 # ifdef USE_OPENSSL
@@ -150,6 +151,7 @@ extern uschar *b64encode_taint(const uschar *, int, BOOL);
 extern int     b64decode(const uschar *, uschar **);
 extern int     bdat_getc(unsigned);
 extern uschar *bdat_getbuf(unsigned *);
+extern BOOL    bdat_hasc(void);
 extern int     bdat_ungetc(int);
 extern void    bdat_flush_data(void);
 
@@ -234,7 +236,7 @@ extern BOOL    dscp_lookup(const uschar *, int, int *, int *, int *);
 extern void    enq_end(uschar *);
 extern BOOL    enq_start(uschar *, unsigned);
 #ifndef DISABLE_EVENT
-extern uschar *event_raise(uschar *, const uschar *, uschar *);
+extern uschar *event_raise(uschar *, const uschar *, uschar *, int *);
 extern void    msg_event_raise(const uschar *, const address_item *);
 #endif
 
@@ -316,8 +318,7 @@ extern int     ip_streamsocket(const uschar *, uschar **, int, host_item *);
 extern int     ipv6_nmtoa(int *, uschar *);
 
 extern uschar *local_part_quote(uschar *);
-extern int     log_create(uschar *);
-extern int     log_create_as_exim(uschar *);
+extern int     log_open_as_exim(uschar * const);
 extern void    log_close_all(void);
 
 extern macro_item * macro_create(const uschar *, const uschar *, BOOL);
@@ -340,6 +341,9 @@ extern int     match_isinlist(const uschar *, const uschar **, int, tree_node **
                  unsigned int *, int, BOOL, const uschar **);
 extern int     match_check_string(const uschar *, const uschar *, int, BOOL, BOOL, BOOL,
                  const uschar **);
+
+extern void    message_start(void);
+extern void    message_tidyup(void);
 extern void    md5_end(md5 *, const uschar *, int, uschar *);
 extern void    md5_mid(md5 *, const uschar *);
 extern void    md5_start(md5 *);
@@ -368,16 +372,19 @@ extern FILE   *modefopen(const uschar *, const char *, mode_t);
 
 extern int     open_cutthrough_connection( address_item * addr );
 
-extern uschar *parse_extract_address(uschar *, uschar **, int *, int *, int *,
+extern uschar *parse_extract_address(const uschar *, uschar **, int *, int *, int *,
                  BOOL);
-extern int     parse_forward_list(uschar *, int, address_item **, uschar **,
+extern int     parse_forward_list(const uschar *, int, address_item **, uschar **,
                  const uschar *, uschar *, error_block **);
-extern uschar *parse_find_address_end(uschar *, BOOL);
-extern uschar *parse_find_at(uschar *);
+extern uschar *parse_find_address_end(const uschar *, BOOL);
+extern const uschar *parse_find_at(const uschar *);
 extern const uschar *parse_fix_phrase(const uschar *, int);
-extern uschar *parse_message_id(uschar *, uschar **, uschar **);
-extern const uschar *parse_quote_2047(const uschar *, int, uschar *, BOOL);
-extern uschar *parse_date_time(uschar *str, time_t *t);
+extern const uschar *parse_message_id(const uschar *, uschar **, uschar **);
+extern const uschar *parse_quote_2047(const uschar *, int, const uschar *,
+                                     BOOL);
+extern const uschar *parse_date_time(const uschar *str, time_t *t);
+extern void priv_drop_temp(const uid_t, const gid_t);
+extern void priv_restore(void);
 extern int     vaguely_random_number(int);
 #ifndef DISABLE_TLS
 extern int     vaguely_random_number_fallback(int);
@@ -405,7 +412,7 @@ extern void    readconf_driver_init(uschar *, driver_instance **,
 extern uschar *readconf_find_option(void *);
 extern void    readconf_main(BOOL);
 extern void    readconf_options_from_list(optionlist *, unsigned, const uschar *, uschar *);
-extern BOOL    readconf_print(uschar *, uschar *, BOOL);
+extern BOOL    readconf_print(const uschar *, uschar *, BOOL);
 extern uschar *readconf_printtime(int);
 extern uschar *readconf_readname(uschar *, int, uschar *);
 extern int     readconf_readtime(const uschar *, int, BOOL);
@@ -422,8 +429,9 @@ extern void    receive_swallow_smtp(void);
 #ifdef WITH_CONTENT_SCAN
 extern int     regex(const uschar **);
 #endif
-extern BOOL    regex_match_and_setup(const pcre *, const uschar *, int, int);
-extern const pcre *regex_must_compile(const uschar *, BOOL, BOOL);
+extern BOOL    regex_match(const pcre2_code *, const uschar *, int, uschar **);
+extern BOOL    regex_match_and_setup(const pcre2_code *, const uschar *, int, int);
+extern const pcre2_code *regex_must_compile(const uschar *, BOOL, BOOL);
 extern void    retry_add_item(address_item *, uschar *, int);
 extern BOOL    retry_check_address(const uschar *, host_item *, uschar *, BOOL,
                  uschar **, uschar **);
@@ -431,16 +439,16 @@ extern retry_config *retry_find_config(const uschar *, const uschar *, int, int)
 extern BOOL    retry_ultimate_address_timeout(uschar *, const uschar *,
                  dbdata_retry *, time_t);
 extern void    retry_update(address_item **, address_item **, address_item **);
-extern uschar *rewrite_address(uschar *, BOOL, BOOL, rewrite_rule *, int);
-extern uschar *rewrite_address_qualify(uschar *, BOOL);
+extern const uschar *rewrite_address(const uschar *, BOOL, BOOL, rewrite_rule *, int);
+extern const uschar *rewrite_address_qualify(const uschar *, BOOL);
 extern header_line *rewrite_header(header_line *,
                const uschar *, const uschar *,
                rewrite_rule *, int, BOOL);
-extern uschar *rewrite_one(uschar *, int, BOOL *, BOOL, uschar *,
+extern const uschar *rewrite_one(const uschar *, int, BOOL *, BOOL, uschar *,
                  rewrite_rule *);
-extern void    rewrite_test(uschar *);
-extern uschar *rfc2047_decode2(uschar *, BOOL, uschar *, int, int *, int *,
-                 uschar **);
+extern void    rewrite_test(const uschar *);
+extern uschar *rfc2047_decode2(uschar *, BOOL, const uschar *, int, int *,
+                                    int *, uschar **);
 extern int     route_address(address_item *, address_item **, address_item **,
                  address_item **, address_item **, int);
 extern int     route_check_prefix(const uschar *, const uschar *, unsigned *);
@@ -470,7 +478,6 @@ extern void    sha1_start(hctx *);
 extern int     sieve_interpret(uschar *, int, uschar *, uschar *, uschar *,
                  uschar *, address_item **, uschar **);
 extern void    sigalrm_handler(int);
-extern BOOL    smtp_buffered(void);
 extern void    smtp_closedown(uschar *);
 extern void    smtp_command_timeout_exit(void) NORETURN;
 extern void    smtp_command_sigterm_exit(void) NORETURN;
@@ -489,7 +496,8 @@ extern BOOL    smtp_get_interface(uschar *, int, address_item *,
 extern BOOL    smtp_get_port(uschar *, address_item *, int *, uschar *);
 extern int     smtp_getc(unsigned);
 extern uschar *smtp_getbuf(unsigned *);
-extern void    smtp_get_cache(void);
+extern void    smtp_get_cache(unsigned);
+extern BOOL    smtp_hasc(void);
 extern int     smtp_handle_acl_fail(int, int, uschar *, uschar *);
 extern void    smtp_log_no_mail(void);
 extern void    smtp_message_code(uschar **, int *, uschar **, uschar **, BOOL);
@@ -519,9 +527,13 @@ extern int     spool_write_header(uschar *, int, uschar **);
 extern int     stdin_getc(unsigned);
 extern int     stdin_feof(void);
 extern int     stdin_ferror(void);
+extern BOOL    stdin_hasc(void);
 extern int     stdin_ungetc(int);
 
 extern void    store_exit(void);
+extern void    store_init(void);
+extern void    store_writeprotect(int);
+
 extern gstring *string_append(gstring *, int, ...) WARN_UNUSED_RESULT;
 extern gstring *string_append_listele(gstring *, uschar, const uschar *) WARN_UNUSED_RESULT;
 extern gstring *string_append_listele_n(gstring *, uschar, const uschar *, unsigned) WARN_UNUSED_RESULT;
@@ -588,8 +600,11 @@ extern BOOL    transport_check_waiting(const uschar *, const uschar *, int, usch
 extern void    transport_init(void);
 extern void    transport_do_pass_socket(const uschar *, const uschar *,
                 const uschar *, uschar *, int);
-extern BOOL    transport_pass_socket(const uschar *, const uschar *, const uschar *, uschar *,
-                 int);
+extern BOOL    transport_pass_socket(const uschar *, const uschar *, const uschar *, uschar *, int
+#ifdef EXPERIMENTAL_ESMTP_LIMITS
+                       , unsigned, unsigned, unsigned
+#endif
+                       );
 extern uschar *transport_rcpt_address(address_item *, BOOL);
 extern BOOL    transport_set_up_command(const uschar ***, uschar *,
                 BOOL, int, address_item *, uschar *, uschar **);
@@ -601,9 +616,9 @@ extern BOOL    transport_headers_send(transport_ctx *,
                  BOOL (*)(transport_ctx *, uschar *, int));
 extern gstring * transport_show_supported(gstring *);
 extern BOOL    transport_write_message(transport_ctx *, int);
-extern void    tree_add_duplicate(uschar *, address_item *);
-extern void    tree_add_nonrecipient(uschar *);
-extern void    tree_add_unusable(host_item *);
+extern void    tree_add_duplicate(const uschar *, address_item *);
+extern void    tree_add_nonrecipient(const uschar *);
+extern void    tree_add_unusable(const host_item *);
 extern void    tree_dup(tree_node **, tree_node *);
 extern int     tree_insertnode(tree_node **, tree_node *);
 extern tree_node *tree_search(tree_node *, const uschar *);
@@ -795,11 +810,11 @@ Returns:  copy of string in new store, with letters lowercased
 */
 
 static inline uschar *
-string_copylc(const uschar *s)
+string_copylc(const uschar * s)
 {
-uschar *ss = store_get(Ustrlen(s) + 1, is_tainted(s));
-uschar *p = ss;
-while (*s != 0) *p++ = tolower(*s++);
+uschar * ss = store_get(Ustrlen(s) + 1, is_tainted(s));
+uschar * p = ss;
+while (*s) *p++ = tolower(*s++);
 *p = 0;
 return ss;
 }
@@ -821,7 +836,7 @@ Returns:    copy of string in new store, with letters lowercased
 */
 
 static inline uschar *
-string_copynlc(uschar *s, int n)
+string_copynlc(uschar * s, int n)
 {
 uschar *ss = store_get(n + 1, is_tainted(s));
 uschar *p = ss;
@@ -961,20 +976,34 @@ g->s = s;
 }
 
 
+# ifndef COMPILE_UTILITY
 /******************************************************************************/
+/* Use store_malloc for DNSA structs, and explicit frees. Using the same pool
+for them as the strings we proceed to copy from them meant they could not be
+released, hence blowing 64k for every DNS lookup. That mounted up. With malloc
+we do have to take care over marking tainted all copied strings.  A separate pool
+could be used and would handle that implicitly. */
 
 #define store_get_dns_answer() store_get_dns_answer_trc(CUS __FUNCTION__, __LINE__)
 
 static inline dns_answer *
 store_get_dns_answer_trc(const uschar * func, unsigned line)
 {
-return store_get_3(sizeof(dns_answer), TRUE, CCS func, line);  /* use tainted mem */
+/* return store_get_3(sizeof(dns_answer), TRUE, CCS func, line);   use tainted mem */
+return store_malloc_3(sizeof(dns_answer), CCS func, line);
+}
+
+#define store_free_dns_answer(dnsa) store_free_dns_answer_trc(dnsa, CUS __FUNCTION__, __LINE__)
+
+static inline void
+store_free_dns_answer_trc(dns_answer * dnsa, const uschar * func, unsigned line)
+{
+store_free_3(dnsa, CCS func, line);
 }
 
 /******************************************************************************/
 /* Routines with knowledge of spool layout */
 
-# ifndef COMPILE_UTILITY
 static inline void
 spool_pname_buf(uschar * buf, int len)
 {
@@ -1040,18 +1069,25 @@ subdir_str[1] = '\0';
 /******************************************************************************/
 /* Time calculations */
 
+/* Diff two times (later, earlier) returning diff in 1st arg */
 static inline void
-timesince(struct timeval * diff, const struct timeval * then)
+timediff(struct timeval * later, const struct timeval * earlier)
 {
-gettimeofday(diff, NULL);
-diff->tv_sec -= then->tv_sec;
-if ((diff->tv_usec -= then->tv_usec) < 0)
+later->tv_sec -= earlier->tv_sec;
+if ((later->tv_usec -= earlier->tv_usec) < 0)
   {
-  diff->tv_sec--;
-  diff->tv_usec += 1000*1000;
+  later->tv_sec--;
+  later->tv_usec += 1000*1000;
   }
 }
 
+static inline void
+timesince(struct timeval * diff, const struct timeval * then)
+{
+gettimeofday(diff, NULL);
+timediff(diff, then);
+}
+
 static inline uschar *
 string_timediff(const struct timeval * diff)
 {
@@ -1095,20 +1131,50 @@ if (f.running_in_test_harness && f.testsuite_delays) millisleep(millisec);
 
 /******************************************************************************/
 /* Taint-checked file opens */
+static inline uschar *
+is_tainted2(const void *p, int lflags, const char* fmt, ...)
+{
+va_list ap;
+uschar *msg;
+rmark mark;
+
+if (!is_tainted(p))
+  return NULL;
+
+mark = store_mark();
+va_start(ap, fmt);
+msg = string_from_gstring(string_vformat(NULL, SVFMT_TAINT_NOCHK|SVFMT_EXTEND, fmt, ap));
+va_end(ap);
+
+#ifdef ALLOW_INSECURE_TAINTED_DATA
+if (allow_insecure_tainted_data)
+  {
+  if LOGGING(tainted) log_write(0, LOG_MAIN, "Warning: %s", msg);
+  store_reset(mark);
+  return NULL;
+  }
+#endif
+
+if (lflags) log_write(0, lflags, "%s", msg);
+return msg; /* no store_reset(), as the message might be used afterwards and Exim
+            is expected to exit anyway, so we do not care about the leaked
+            storage */
+}
 
 static inline int
 exim_open2(const char *pathname, int flags)
 {
-if (!is_tainted(pathname)) return open(pathname, flags);
-log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname);
+if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname))
+  return open(pathname, flags);
 errno = EACCES;
 return -1;
 }
+
 static inline int
 exim_open(const char *pathname, int flags, mode_t mode)
 {
-if (!is_tainted(pathname)) return open(pathname, flags, mode);
-log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname);
+if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname))
+  return open(pathname, flags, mode);
 errno = EACCES;
 return -1;
 }
@@ -1116,16 +1182,16 @@ return -1;
 static inline int
 exim_openat(int dirfd, const char *pathname, int flags)
 {
-if (!is_tainted(pathname)) return openat(dirfd, pathname, flags);
-log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname);
+if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname))
+  return openat(dirfd, pathname, flags);
 errno = EACCES;
 return -1;
 }
 static inline int
 exim_openat4(int dirfd, const char *pathname, int flags, mode_t mode)
 {
-if (!is_tainted(pathname)) return openat(dirfd, pathname, flags, mode);
-log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname);
+if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname))
+  return openat(dirfd, pathname, flags, mode);
 errno = EACCES;
 return -1;
 }
@@ -1134,8 +1200,8 @@ return -1;
 static inline FILE *
 exim_fopen(const char *pathname, const char *mode)
 {
-if (!is_tainted(pathname)) return fopen(pathname, mode);
-log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname);
+if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname))
+  return fopen(pathname, mode);
 errno = EACCES;
 return NULL;
 }
@@ -1143,8 +1209,8 @@ return NULL;
 static inline DIR *
 exim_opendir(const uschar * name)
 {
-if (!is_tainted(name)) return opendir(CCS name);
-log_write(0, LOG_MAIN|LOG_PANIC, "Tainted dirname '%s'", name);
+if (!is_tainted2(name, LOG_MAIN|LOG_PANIC, "Tainted dirname '%s'", name))
+  return opendir(CCS name);
 errno = EACCES;
 return NULL;
 }
@@ -1188,6 +1254,14 @@ child_open(uschar **argv, uschar **envp, int newumask, int *infdptr,
   outfdptr, make_leader, purpose);
 }
 
+/* Return 1 if fd is usable per pollbits, else 0 */
+static inline int
+poll_one_fd(int fd, short pollbits, int tmo_millisec)
+{
+struct pollfd p = {.fd = fd, .events = pollbits};
+return poll(&p, 1, tmo_millisec);
+}
+
 # endif        /* !COMPILE_UTILITY */
 
 /******************************************************************************/