1 /* This file is part of Mailfromd. 2 Copyright (C) 2005-2021 Sergey Poznyakoff 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 3, or (at your option) 7 any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16 17 #include <sys/time.h> 18 #include <sys/types.h> 19 #include <unistd.h> 20 #include <stdio.h> 21 #include <gettext.h> 22 #include <limits.h> 23 #include <mailutils/types.h> 24 #include <mailutils/cfg.h> 25 #include <mailutils/stdstream.h> 26 #include <mailutils/cli.h> 27 #include <pwd.h> 28 #include <grp.h> 29 30 #include "dns.h" 31 32 #define _(String) gettext(String) 33 #define N_(String) String 34 35 #if defined HAVE_SYSCONF && defined _SC_OPEN_MAX 36 # define getmaxfd() sysconf(_SC_OPEN_MAX) 37 #elif defined (HAVE_GETDTABLESIZE) 38 # define getmaxfd() getdtablesize() 39 #else 40 # define getmaxfd() 256 41 #endif 42 43 44 /* The following defines are borrowed from intprops.h (gnulib) */ 45 46 /* True if the arithmetic type T is signed. */ 47 #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) 48 49 /* Return zero if T can be determined to be an unsigned type. 50 Otherwise, return 1. 51 When compiling with GCC, INT_STRLEN_BOUND uses this macro to obtain a 52 tighter bound. Otherwise, it overestimates the true bound by one byte 53 when applied to unsigned types of size 2, 4, 16, ... bytes. 54 The symbol signed_type_or_expr__ is private to this header file. */ 55 #if __GNUC__ >= 2 56 # define signed_type_or_expr__(t) TYPE_SIGNED (__typeof__ (t)) 57 #else 58 # define signed_type_or_expr__(t) 1 59 #endif 60 61 /* Bound on length of the string representing an integer type or expression T. 62 Subtract 1 for the sign bit if T is signed; log10 (2.0) < 146/485; 63 add 1 for integer division truncation; add 1 more for a minus sign 64 if needed. */ 65 #define INT_STRLEN_BOUND(t) \ 66 ((sizeof (t) * CHAR_BIT - signed_type_or_expr__ (t)) * 146 / 485 \ 67 + signed_type_or_expr__ (t) + 1) 68 69 /* Bound on buffer size needed to represent an integer type or expression T, 70 including the terminating null. */ 71 #define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1) 72 73 /* Size of the buffer able to accomodate mailfromd numeric type */ 74 #define NUMERIC_BUFSIZE_BOUND INT_BUFSIZE_BOUND(long) 75 76 77 /* Status values used throughout the program */ 78 typedef enum mf_status_code { 79 mf_success, 80 mf_not_found, 81 mf_failure, 82 mf_temp_failure, 83 mf_timeout, 84 85 #define mf_status_count (mf_smtp_temp_failure+1) 86 } mf_status; 87 88 #define mf_resolved(c) ((c) == mf_success || (c) == mf_not_found) 89 90 const char *mf_status_str(mf_status s); 91 92 93 enum smtp_timeout { 94 smtp_timeout_connect, 95 smtp_timeout_initial, 96 smtp_timeout_helo, 97 smtp_timeout_mail, 98 smtp_timeout_rcpt, 99 smtp_timeout_rset, 100 smtp_timeout_quit 101 }; 102 103 #define SMTP_NUM_TIMEOUT (smtp_timeout_quit+1) 104 105 106 #define MF_GETOPT_DEFAULT 0x00 107 /* Process options in order; don't permute */ 108 #define MF_GETOPT_IN_ORDER 0x01 109 /* Don't parse configuration files */ 110 #define MF_GETOPT_NO_CONFIG 0x02 111 112 void mf_getopt(struct mu_cli_setup *cli, int *pargc, char ***pargv, char **capa, 113 int flags); 114 void mailfromd_version(struct mu_parseopt *po, mu_stream_t stream); 115 int mf_vercmp(const char *a, const char *b, int *pres); 116 void mf_init_nls (void); 117 int parse_time_interval(const char *str, time_t *pint, const char **endp); 118 119 void dict_init(mu_assoc_t *dict); 120 char *dict_install(mu_assoc_t dict, const char *name, const char *value); 121 void dict_destroy(mu_assoc_t *dict); 122 char *dict_getsym(void *data, const char *str); 123 124 125 struct mf_privs { 126 char *user; 127 int allgroups; 128 mu_list_t groups; 129 }; 130 131 struct mf_gid_list; 132 133 struct mf_gid_list *mf_gid_list_alloc(void); 134 void mf_gid_list_free(struct mf_gid_list *gl); 135 struct mf_gid_list *mf_gid_list_dup(struct mf_gid_list *src); 136 void mf_gid_list_add(struct mf_gid_list *gl, gid_t gid); 137 void mf_gid_list_array(struct mf_gid_list *gl, size_t *gc, gid_t **gv); 138 139 int switch_to_privs (uid_t uid, gid_t gid, struct mf_gid_list *); 140 void get_user_groups (struct mf_gid_list *grouplist, const char *user); 141 142 void mf_priv_setup (struct mf_privs *); 143 void mf_epriv_setup (struct mf_privs *); 144 145 146 char **config_array_to_argv (mu_config_value_t *val); 147 char *config_array_to_string (mu_config_value_t *val); 148 149 int config_cb_timeout (struct timeval *pt, mu_config_value_t *val); 150 int config_cb_time_t(void *data, mu_config_value_t *arg); 151 int config_cb_ignore(void *data, mu_config_value_t *val); 152 int config_cb_lock_retry_count(void *data, mu_config_value_t *val); 153 int config_cb_lock_retry_timeout(void *data, mu_config_value_t *val); 154 155 void mf_proctitle_init (int argc, char *argv[], char *env[]); 156 void mf_proctitle_format (const char *fmt, ...); 157 int stderr_closed_p(void); 158 int mf_list_compare_string(const void *item, const void *value); 159 160 161 struct symtab; 162 struct syment { 163 char *name; 164 unsigned refcnt; 165 }; 166 167 typedef int (*symtab_enumerator_t)(void *sym, void *data); 168 169 #define SYMTAB_COPY_KEY 0x1 170 #define SYMTAB_ICASE 0x2 171 172 const char * symtab_strerror(int rc); 173 174 int symtab_lookup_or_install(struct syment **ent, 175 struct symtab *st, const char *name, 176 int *install); 177 int symtab_lookup_or_install_entry(struct syment **elp, 178 struct symtab *st, struct syment *ent, 179 int *install); 180 void symtab_clear(struct symtab *st); 181 struct symtab *symtab_create(size_t elsize, int flags, 182 void *(*alloc_fun)(size_t), 183 void (*free_fun)(void *)); 184 void symtab_destroy(struct symtab **pst); 185 int symtab_remove(struct symtab *st, const char *name); 186 int symtab_replace(struct symtab *st, struct syment *ent, 187 struct syment **old_ent); 188 int symtab_enumerate(struct symtab *st, symtab_enumerator_t fun, void *data); 189 190 191 typedef int (*symtab_selfun)(const struct syment *ent, void *closure); 192 typedef int (*symtab_errfun)(int rc, struct symtab *tab, const char *name, 193 void *closure); 194 typedef int (*symtab_confun)(struct symtab *dst, 195 struct syment *dstent, struct syment *srcent, 196 void *closure); 197 typedef int (*symtab_cpyfun)(struct syment **pdst, struct syment *src, 198 size_t len, void *closure); 199 200 int symtab_import(struct symtab *dst, struct symtab *src, 201 symtab_selfun selfun, symtab_errfun errfun, 202 symtab_confun confun, symtab_cpyfun cpyfun, 203 void *closure); 204 205 size_t symtab_count_entries(struct symtab *st); 206 207 208 typedef struct transform *transform_t; 209 210 const char *transform_error_string (void); 211 transform_t transform_compile(const char *expr, int cflags); 212 void transform_free(transform_t); 213 char *transform_string (transform_t tf, const char *input); 214 transform_t transform_join (transform_t dst, transform_t src); 215 216 217 void close_fds_above(int fd); 218 void close_fds_except(fd_set *exfd); 219 220 /* logger.c */ 221 #ifdef DEFAULT_SYSLOG_ASYNC 222 # define DEFAULT_LOG_STREAM "syslog:async" 223 #else 224 # define DEFAULT_LOG_STREAM "syslog" 225 #endif 226 227 #define LOGF_STDERR 0x01 /* Logger uses stderr */ 228 229 struct logger { 230 char *name; 231 int flags; 232 void (*log_open)(void); 233 void (*log_close)(void); 234 void (*log_fdset)(fd_set *set); 235 void (*log_text)(int, const char *); 236 }; 237 238 int logger_flags(int mask); 239 int logger_select(const char *name); 240 void logger_open(void); 241 void logger_close(void); 242 void logger_fdset(fd_set *set); 243 void logger_text(int prio, const char *text); 244 245 #define vlogmsg mu_diag_voutput 246 #define logmsg mu_diag_output 247 248 249 /* strmwait.c */ 250 251 struct timeout_ctl { 252 time_t start; 253 time_t timeout; 254 }; 255 256 #define UPDATE_TTW(t) do { \ 257 time_t now = time(NULL); \ 258 time_t delta = now - (t).start; \ 259 if ((t).timeout > delta) \ 260 (t).timeout -= delta; \ 261 else \ 262 (t).timeout = 0; \ 263 (t).start = now; \ 264 } while (0) 265 266 void init_timeout_ctl(struct timeout_ctl *tctl, time_t timeout); 267 int mf_stream_wait(mu_stream_t stream, int flags, struct timeout_ctl *tctl); 268 269 270 /* ftimestr.c */ 271 extern char *time_format_string; 272 273 size_t format_time_str(FILE *fp, time_t timestamp); 274 275 276 /* dns.c */ 277 void dnsbase_init(void); 278 mf_status dns_to_mf_status(dns_status stat); 279 dns_status mf_to_dns_status(mf_status stat); 280 mf_status resolve_ipstr_domain(const char *ipstr, const char *domain, char **phbuf); 281 mf_status resolve_ipstr(const char *ipstr, char **phbuf); 282 mf_status resolve_hostname(const char *host, char **pipbuf); 283 284 285 /* server.c */ 286 287 #define MF_SERVER_FOREGROUND 0x01 288 #define MF_SERVER_NORESTART 0x02 289 290 extern void mf_server_log_setup(void); 291 292 extern mode_t mf_server_umask; 293 extern char *mf_server_user; 294 extern struct mf_gid_list *mf_server_retain_groups; 295 extern char *mf_server_lint_option; 296 297 void mf_server_check_pidfile(const char *name); 298 void mf_server_save_cmdline(int argc, char **argv); 299 void mf_server_start(const char *program, const char *dir, 300 const char *pidfile, int flags); 301 302 303 /* namefixup.c */ 304 void mf_namefixup_register(char **ptr, const char *initval); 305 void mf_file_name_ptr_fixup(char **ptr, char *dir, size_t dirlen); 306 void mf_namefixup_run(char *dir); 307 void mf_namefixup_free(void); 308 309