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