aboutsummaryrefslogtreecommitdiff
path: root/gacopyz/gacopyz.h
blob: e52d32f16f73f46bd566d8740df9a289f7d78f30 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
/* This file is part of gacopyz.
   Copyright (C) 2006, 2007 Sergey Poznyakoff

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */

#ifndef __gacopyz_h__
# define __gacopyz_h__

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <syslog.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>

#ifdef __cplusplus
extern "C" {
#endif

#define GACOPYZ_VERSION_MAJOR 1
#define GACOPYZ_VERSION_MINOR 0
	
/* Implementation version number */	
#define SMFI_VERSION   2
	
/* commands: don't use anything smaller than ' ' */
#define SMFIC_ABORT             'A'     /* Abort */
#define SMFIC_BODY              'B'     /* Body chunk */
#define SMFIC_CONNECT           'C'     /* Connection information */
#define SMFIC_MACRO             'D'     /* Define macro */
#define SMFIC_BODYEOB           'E'     /* final body chunk (End) */
#define SMFIC_HELO              'H'     /* HELO/EHLO */
#define SMFIC_HEADER            'L'     /* Header */
#define SMFIC_MAIL              'M'     /* MAIL from */
#define SMFIC_EOH               'N'     /* EOH */
#define SMFIC_OPTNEG            'O'     /* Option negotiation */
#define SMFIC_QUIT              'Q'     /* QUIT */
#define SMFIC_RCPT              'R'     /* RCPT to */
#define SMFIC_DATA              'T'     /* DATA (SMFI_VERSION > 3) */
#define SMFIC_UNKNOWN           'U'     /* Any unknown command */

/* actions (replies) */
#define SMFIR_ADDRCPT           '+'     /* add recipient */
#define SMFIR_DELRCPT           '-'     /* remove recipient */
#define SMFIR_ACCEPT            'a'     /* accept */
#define SMFIR_REPLBODY          'b'     /* replace body (chunk) */
#define SMFIR_CONTINUE          'c'     /* continue */
#define SMFIR_DISCARD           'd'     /* discard */
#define SMFIR_CONN_FAIL         'f'     /* cause a connection failure */
#define SMFIR_CHGHEADER         'm'     /* change header */
#define SMFIR_PROGRESS          'p'     /* progress */
#define SMFIR_REJECT            'r'     /* reject */
#define SMFIR_TEMPFAIL          't'     /* tempfail */
#define SMFIR_SHUTDOWN          '4'     /* 421: shutdown (internal to MTA) */
#define SMFIR_ADDHEADER         'h'     /* add header */
#define SMFIR_INSHEADER         'i'     /* insert header */
#define SMFIR_REPLYCODE         'y'     /* reply code etc */
#define SMFIR_QUARANTINE        'q'     /* quarantine */

/* What the MTA can send/filter wants in protocol */
#define SMFIP_NOCONNECT 0x00000001L     /* MTA should not send connect info */
#define SMFIP_NOHELO    0x00000002L     /* MTA should not send HELO info */
#define SMFIP_NOMAIL    0x00000004L     /* MTA should not send MAIL info */
#define SMFIP_NORCPT    0x00000008L     /* MTA should not send RCPT info */
#define SMFIP_NOBODY    0x00000010L     /* MTA should not send body */
#define SMFIP_NOHDRS    0x00000020L     /* MTA should not send headers */
#define SMFIP_NOEOH     0x00000040L     /* MTA should not send EOH */
#define SMFIP_NOHREPL   0x00000080L     /* No reply for headers */
#define SMFIP_NOUNKNOWN 0x00000100L     /* MTA should not send unknown
                                           command */
#define SMFIP_NODATA    0x00000200L     /* MTA should not send DATA */

/* The protocol of V1 filter */
#define SMFI_V1_PROT    (SMFIP_NOCONNECT|SMFIP_NOHELO|SMFIP_NOMAIL|\
                         SMFIP_NORCPT|SMFIP_NOBODY|SMFIP_NOHDRS)
/* The protocol of V2 filter */	
#define SMFI_V2_PROT    (SMFI_V1_PROT|SMFIP_NOEOH)

/* Flags, defining milter capabilities */
#define SMFIF_NONE	0x00000000L	/* no flags */
#define SMFIF_ADDHDRS	0x00000001L	/* filter may add headers */
#define SMFIF_CHGBODY	0x00000002L	/* filter may replace body */
#define SMFIF_MODBODY	SMFIF_CHGBODY	/* backwards compatible */
#define SMFIF_ADDRCPT	0x00000004L	/* filter may add recipients */
#define SMFIF_DELRCPT	0x00000008L	/* filter may delete recipients */
#define SMFIF_CHGHDRS	0x00000010L	/* filter may change/delete headers */
#define SMFIF_QUARANTINE 0x00000020L	/* filter may quarantine envelope */

#define SMFI_V1_ACTS (SMFIF_ADDHDRS|SMFIF_CHGBODY|SMFIF_ADDRCPT|SMFIF_DELRCPT)
#define SMFI_V2_ACTS (SMFI_V1_ACTS|SMFIF_CHGHDRS|SMFIF_QUARANTINE)	

#define SMFI_DEFAULT_ACTS SMFI_V2_ACTS
#define SMFI_DEFAULT_PROT SMFI_V2_PROT	
	
/* Log levels */	
#define SMI_LOG_DEBUG   0
#define SMI_LOG_INFO    1
#define SMI_LOG_WARN    2
#define SMI_LOG_ERR     3
#define SMI_LOG_FATAL   4

#define SMI_LOG_MASK(n) (1<<(n))
#define SMI_LOG_UPTO(n) ((1 << ((n)+1))-1)  /* all levels through n */
#define SMI_LOG_FROM(n) (SMI_LOG_UPTO(SMI_LOG_FATAL) & ~SMI_LOG_UPTO(n-1))
			 
#define SMI_DEFAULT_LOG_MASK SMI_LOG_MASK(SMI_LOG_INFO)   \
                             | SMI_LOG_MASK(SMI_LOG_WARN) \
                 	     | SMI_LOG_MASK(SMI_LOG_ERR)  \
		             | SMI_LOG_MASK(SMI_LOG_FATAL)

/* address families */
#define SMFIA_UNKNOWN 'U'     /* unknown */
#define SMFIA_UNIX    'L'     /* unix/local */
#define SMFIA_INET    '4'     /* inet */
#define SMFIA_INET6   '6'     /* inet6 */

/* Function return codes */
#define MI_SUCCESS	0
#define MI_FAILURE	(-1)

/* Data types */
typedef struct smfi_str SMFICTX;
typedef struct smfi_str *SMFICTX_PTR;
typedef struct gacopyz_conn *gacopyz_conn_t;
typedef struct gacopyz_iod *gacopyz_iod_t;
	
/* Return type for the callbacks */
typedef enum {
	SMFIS_CONTINUE,
	SMFIS_REJECT,
	SMFIS_DISCARD,
	SMFIS_ACCEPT,
	SMFIS_TEMPFAIL
} sfsistat;

typedef union {
	struct sockaddr sa;
	struct sockaddr_in sin;
	struct sockaddr_un sunix;
} milter_sockaddr_t;

#define _SOCK_ADDR milter_sockaddr_t	

struct smfiDesc
{
        char          *xxfi_name;     /* filter name */
        int           xxfi_version;   /* version code */
        unsigned long xxfi_flags;     /* flags */
	  /* Filters: */
          /* connection info */
        sfsistat    (*xxfi_connect) (SMFICTX *, char *, milter_sockaddr_t *);
          /* SMTP HELO command */
        sfsistat    (*xxfi_helo) (SMFICTX *, char *);
          /* envelope sender */
        sfsistat    (*xxfi_envfrom) (SMFICTX *, char **);
          /* envelope recipient */
        sfsistat    (*xxfi_envrcpt) (SMFICTX *, char **);
          /* header */
        sfsistat    (*xxfi_header) (SMFICTX *, char *, char *);
          /* end of header */
        sfsistat    (*xxfi_eoh) (SMFICTX *);
          /* body block */
        sfsistat    (*xxfi_body) (SMFICTX *, unsigned char *, size_t);
          /* end of message */
        sfsistat     (*xxfi_eom) (SMFICTX *);
          /* message aborted */
        sfsistat     (*xxfi_abort) (SMFICTX *);
          /* connection cleanup */
        sfsistat     (*xxfi_close) (SMFICTX *);
          /* any unrecognized or unimplemented command (SMFI_VERSION > 2) */
        sfsistat     (*xxfi_unknown) (SMFICTX *, char *);
          /* SMTP DATA command (SMFI_VERSION > 3) */
        sfsistat     (*xxfi_data) (SMFICTX *);

	/* Extensions: */

	int (*xxfi_start) (void);         /* Child start callback */
	int (*xxfi_finish) (void);        /* Child finish callback */
	int (*xxfi_idle) (gacopyz_conn_t); /* Idle handler */
};

/* Standard API calls */
extern int smfi_opensocket (int);
extern int smfi_register (struct smfiDesc);
extern int smfi_main (void);
extern int smfi_setbacklog (int);
extern int smfi_setdbg (int);
extern int smfi_settimeout (time_t);
extern int smfi_setconn (char *);
extern int smfi_stop (void);
	
#define smfi_getsymval gacopyz_getsymval 

int smfi_addheader (SMFICTX *, char *, char *);
int smfi_chgheader (SMFICTX *, char *, int, char *);
int smfi_insheader (SMFICTX *, int, char *, char *);
int smfi_addrcpt (SMFICTX *, char *);
int smfi_delrcpt (SMFICTX *, char *);
int smfi_progress (SMFICTX *);
int smfi_replacebody (SMFICTX *, unsigned char *, int);
int smfi_quarantine (SMFICTX *ctx, char *reason);
#define smfi_setpriv gacopyz_setpriv
#define smfi_getpriv gacopyz_getpriv
size_t smfi_setmaxdatasize (size_t); 

/* Replies: */
extern int smfi_setreply (SMFICTX *, char *, char *, char *);
int smfi_setmlreply (SMFICTX *, const char *, const char *, ...);

/* Extensions */	
extern int smfi_set_foreground(int val);
extern int smfi_setlogmask(int logmask);

/* New API calls: */
int gacopyz_init(gacopyz_conn_t *pconn, struct smfiDesc *desc);
void gacopyz_free(gacopyz_conn_t conn);

int gacopyz_set_logmask(gacopyz_conn_t conn, int mask);
int gacopyz_get_logmask(gacopyz_conn_t conn, int *mask);
int gacopyz_set_foreground(gacopyz_conn_t conn, int fg);
int gacopyz_set_master_timeout(gacopyz_conn_t conn, struct timeval *timeout);
int gacopyz_get_master_timeout(gacopyz_conn_t conn, struct timeval *timeout);
int gacopyz_set_ctx_timeout(gacopyz_conn_t conn, struct timeval *timeout);
int gacopyz_get_ctx_timeout(gacopyz_conn_t conn, struct timeval *timeout);
int gacopyz_stop(gacopyz_conn_t conn);
	
int gacopyz_open(gacopyz_conn_t conn, const char *cstr,
		  int backlog, int rmsocket);
	
int gacopyz_parse_connection(const char *cstr,
			     char **pproto, char **pport, char **ppath);

int gacopyz_connect(gacopyz_conn_t *, struct smfiDesc *, const char *,
		    int backlog, int rmsocket);
int gacopyz_get_fd(gacopyz_conn_t);
	
int gacopyz_run(gacopyz_conn_t);	

int gacopyz_register_child(gacopyz_conn_t conn, pid_t pid);
void gacopyz_cleanup_children(gacopyz_conn_t conn);
void gacopyz_cleanup_conn(gacopyz_conn_t conn);
void gacopyz_setup_signals(void);

char *gacopyz_getsymval (SMFICTX *, char *);	

int gacopyz_setreply(SMFICTX *ctx, const char *rcode, const char *xcode,
		      const char *message);
int gacopyz_setmlreply_v(SMFICTX *ctx, const char *rcode, const char *xcode,
			  ...);
int gacopyz_setmlreply_va(SMFICTX *ctx, const char *rcode, const char *xcode,
			   va_list ap);
int _gacopyz_setmlreply_va(SMFICTX *ctx, size_t max, const char *rcode,
			    const char *xcode, va_list ap);

int gacopyz_add_header(SMFICTX *ctx, const char *headerf,
			const char *headerv);

int gacopyz_insert_header(SMFICTX *ctx, int index, const char *headerf,
			   const char *headerv);
int gacopyz_change_header(SMFICTX *ctx, int index, const char *headerf,
			   const char *headerv);
int gacopyz_add_rcpt(SMFICTX *ctx, const char *rcpt);
int gacopyz_del_rcpt(SMFICTX *ctx, const char *rcpt);
int gacopyz_replace_body(SMFICTX *ctx, unsigned char *bodyp, size_t bodylen);
int gacopyz_progress(SMFICTX *ctx);
int gacopyz_quarantine(SMFICTX *ctx, const char *reason);

int gacopyz_setpriv (SMFICTX *ctx, void *data);
void *gacopyz_getpriv (SMFICTX *ctx);
	
/* Logging (extensions) */
#define GACOPYZ_VBUFSIZE 69
size_t gacopyz_format_vbuf(char vbuf[GACOPYZ_VBUFSIZE], const char *buf,
			   size_t size);
void gacopyz_log(gacopyz_conn_t conn, int level, char *fmt, ...);
void gacopyz_io_log(gacopyz_iod_t iod, int level, char *fmt, ...);
void gacopyz_logmsg(int level, char *fmt, ...);
void _gacopyz_logdump(int logmask, int level, const char *pfx, const char *buf,
		      size_t size);
void gacopyz_logdump(gacopyz_conn_t conn, int level, const char *pfx,
		     const char *buf, size_t size);
void gacopyz_io_logdump(gacopyz_iod_t iod, int level, const char *pfx,
			const char *buf, size_t size);
void gacopyz_set_logger(void (*)(int, char *, va_list));

void gacopyz_stderr_log_printer(int level, char *fmt, va_list ap);
void gacopyz_syslog_log_printer(int level, char *fmt, va_list ap);
int gacopyz_string_to_log_level(const char *str);
const char *gacopyz_log_level_to_string(int level);
	
	
/* Server */
typedef struct gacopyz_srv *gacopyz_srv_t;

int gacopyz_srv_create(gacopyz_srv_t *p, const char *name,
		       const char *portspec, unsigned logmask);
int gacopyz_srv_create_X(gacopyz_srv_t *p, const char *spec, unsigned logmask);
	
void gacopyz_srv_destroy(gacopyz_srv_t *p);	
int gacopyz_srv_find_macro (gacopyz_srv_t srv, const char *name,
			    const char **pval);
void gacopyz_srv_define_macro (gacopyz_srv_t srv,
			      const char *name, const char *value);
void gacopyz_srv_define_macro0 (gacopyz_srv_t srv,
				const char *name, const char *value,
				int overwrite);
void gacopyz_srv_del_macro (gacopyz_srv_t srv, const char *name);
void gacopyz_srv_clear_macros (gacopyz_srv_t srv);
void gacopyz_srv_iterate_macros (gacopyz_srv_t srv,
				 int (*func) (const char *name,
					      const char *value,
					      void *data),
				 void *data);
void gacopyz_srv_count_macros (gacopyz_srv_t srv, size_t *count);
int gacopyz_srv_connect (gacopyz_srv_t srv);
int gacopyz_srv_init(gacopyz_srv_t srv);
int gacopyz_srv_negotiate(gacopyz_srv_t srv);
int gacopyz_srv_abort(gacopyz_srv_t srv);
int gacopyz_srv_quit(gacopyz_srv_t srv);

int gacopyz_srv_helo (gacopyz_srv_t p, const char *domain);
int gacopyz_srv_envfrom (gacopyz_srv_t p, char **argv);
int gacopyz_srv_envrcpt (gacopyz_srv_t p, char **argv);
int gacopyz_srv_header (gacopyz_srv_t p, char *name, char *value);
int gacopyz_srv_eoh (gacopyz_srv_t p);
int gacopyz_srv_body (gacopyz_srv_t p, unsigned char *str, size_t size);

int gacopyz_srv_eom (gacopyz_srv_t p, unsigned char *str, size_t size);
int gacopyz_srv_abort (gacopyz_srv_t p);
int gacopyz_srv_close (gacopyz_srv_t p);
int gacopyz_srv_data (gacopyz_srv_t p);

int gacopyz_srv_onerror(gacopyz_srv_t srv, int code);
void gacopyz_srv_set_memerror(gacopyz_srv_t srv,
			      void (*memerror)(gacopyz_srv_t, const char *,
					       unsigned int));
	
int gacopyz_srv_set_source(gacopyz_srv_t srv, unsigned long addr);
int gacopyz_srv_set_version(gacopyz_srv_t srv, int version);
int gacopyz_srv_set_protocol(gacopyz_srv_t srv, int proto);
int gacopyz_srv_set_actions(gacopyz_srv_t srv, int acts);

#define GACOPYZ_WRITE_TIMEOUT 10
#define GACOPYZ_READ_TIMEOUT 10
#define GACOPYZ_EOM_TIMEOUT 300
#define GACOPYZ_CONNECT_TIMEOUT 300	
	
#define GACOPYZ_TO_WRITE    0    /* Timeout for sending information */
#define GACOPYZ_TO_READ     1    /* Timeout waiting for a response */
#define GACOPYZ_TO_EOM      2    /* Timeout for ACK/NAK to EOM */
#define GACOPYZ_TO_CONNECT  3    /* Timeout for connect() */
#define GACOPYZ_TO_COUNT    4

void gacopyz_srv_set_all_timeouts(gacopyz_srv_t srv, struct timeval *tvp);
int gacopyz_srv_set_timeout(gacopyz_srv_t srv, unsigned n,
			    struct timeval *tvp);
int gacopyz_srv_set_timeout_sec(gacopyz_srv_t srv, unsigned n, time_t t);
	
void gacopyz_srv_reply(gacopyz_srv_t srv, char **msg, size_t *size);
	
#ifdef __cplusplus
}
#endif

#endif /* __gacopyz_h__ */

Return to:

Send suggestions and report system problems to the System administrator.