1 #include "policyd.h"
2
3 /*
4 *
5 *
6 * Policy Daemon
7 *
8 * policy daemon is used in conjuction with postfix to combat spam.
9 *
10 * Copyright (C) 2007 Nigel Kukard <nkukard@lbsd.net>
11 * Copyright (C) 2004 Cami Sardinha (cami@mweb.co.za)
12 *
13 *
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2 of the License, or (at your
17 * option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
23 *
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 *
28 *
29 *
30 */
31
32 /*
33 * function: w_select (function_select)
34 * purpose: wrapper for select()
35 */
36 int
w_select(int nfds,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout)37 w_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
38 {
39 int n;
40 if ((n=select(nfds, readfds, writefds, exceptfds, timeout)) < 0)
41 {
42 if (errno == EINTR)
43 {
44 logmessage("warning: select(): system interupt\n");
45 return 0;
46 }
47 if (errno == EBADF)
48 {
49 logmessage("warning: select(): descriptor was not open\n");
50 return 0;
51 }
52
53 logmessage("fatal: select(): %s\n", strerror(errno));
54 exit(-1);
55 }
56
57 return(n);
58 }
59
60
61
62
63 /*
64 * function: w_accept (wrapped_select)
65 * purpose: wrapped for accept()
66 * return: file descriptor
67 */
68 int
w_accept(unsigned int fd,struct sockaddr * sa,socklen_t * salenptr)69 w_accept(unsigned int fd, struct sockaddr *sa, socklen_t *salenptr)
70 {
71 int n;
72
73 again:
74
75 if ((n = accept(fd, sa, salenptr)) < 0)
76 {
77 #ifdef EPROTO
78 if (errno == EPROTO || errno == ECONNABORTED)
79 {
80 #else
81 if (errno == ECONNABORTED)
82 {
83 #endif
84 if(DEBUG > 2)
85 logmessage("DEBUG: fd: %d accept(): %s: retrying\n", fd, strerror(errno));
86
87 goto again;
88 } else {
89 logmessage("fatal: accept(): %s (MAXFDS=%d ENV=%d)\n", strerror(errno), MAXFDS, getdtablesize());
90 exit(-1);
91 }
92 }
93
94 return(n);
95 }
96
97
98
99
100 /*
101 * function: w_bind (wrapper_bind)
102 * purpose: wrapper for bind()
103 */
104 void
105 w_bind(unsigned int fd, const struct sockaddr *sa, socklen_t salen)
106 {
107 u_int yes=1;
108
109 /* set options on socket (reuse port/address) */
110 if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0)
111 {
112 logmessage("fatal: setsockopt(): %s\n", strerror(errno));
113 exit(-1);
114 }
115
116 /* bind a name to a socket */
117 if (bind(fd, sa, salen) < 0)
118 {
119 logmessage("fatal: bind(): %s\n", strerror(errno));
120 exit(-1);
121 }
122 }
123
124
125
126
127 /*
128 * function: w_listen (wrapper_listen)
129 * purpose: wrapper for listen()
130 */
131 void
132 w_listen(unsigned int fd, unsigned int backlog)
133 {
134 /* listen for connection on a socket */
135 if (listen(fd, backlog) < 0)
136 {
137 logmessage("fatal: listen(): %s\n", strerror(errno));
138 exit(-1);
139 }
140 }
141
142
143
144
145 /*
146 * function: w_read (function_read)
147 * purpose: read number of bytes read
148 * return: number bytes read
149 */
150 ssize_t
151 w_read(unsigned int fd, char *ptr, size_t max_size)
152 {
153 ssize_t n;
154 size_t data_read = 0; /* for debug only */
155
156 /* receive data. disable signals are do not wait */
157 while ((n = recv(fd, (void *) ptr + buf_counter[fd], 1, MSG_DONTWAIT | MSG_NOSIGNAL)) == 1)
158 {
159 data_read++;
160 buf_counter[fd]++;
161 buf_size[fd]++;
162
163
164 /* check if we've reached the end of the buffer */
165 if (buf_counter[fd] >= max_size)
166 {
167 if (DEBUG > 2)
168 logmessage("DEBUG: fd: %d reached end of buffer, aborting\n", fd);
169
170 return -3;
171 }
172
173 /* need at least 2 bytes to check against */
174 if (buf_counter[fd] > 2)
175 {
176 /* received policy protocol terminator */
177 if (strncmp(ptr + buf_counter[fd] - 2, "\n\n", 2) == 0)
178 {
179 if (DEBUG > 2)
180 logmessage("DEBUG: fd %d: %s: returning -2 after reading %d bytes\n",fd, __FUNCTION__, data_read);
181
182 return -2;
183 }
184 }
185 }
186
187 /* check if recv returned an error */
188 if (n == -1)
189 {
190 /* Ignore EAGAIN */
191 if (errno == EAGAIN)
192 {
193 if (DEBUG > 2)
194 logmessage("DEBUG: fd: %d returning data_read = %d after EAGAIN\n", fd, data_read);
195
196 return data_read;
197 }
198
199 /* here something bad happened */
200 if (DEBUG > 2)
201 logmessage("DEBUG: fd: %d connection problem during read: %s\n", fd, strerror(errno));
202
203 return -1;
204 }
205
206 /* EOF was reached if n == 0 */
207 if (n == 0)
208 {
209 if(DEBUG > 2)
210 logmessage("DEBUG: fd: %d connection got an EOF, data_read = %d\n", fd, data_read);
211
212 return -1;
213 }
214
215 if (DEBUG > 2)
216 logmessage("DEBUG: fd: %d returning data_read = %d\n", fd, data_read);
217
218 /* return total amount of bytes read */
219 return data_read;
220 }
221
222
223
224
225 /*
226 * function: buf_write
227 * purpose: prepare buffer that needs to be written
228 * return:
229 */
230 void
231 buf_write(unsigned int fd, const char *ptr, size_t nbytes)
232 {
233 memcpy(buf[fd], (void *) ptr, nbytes);
234
235 buf_counter[fd] = 0;
236 buf_size[fd] = nbytes;
237 }
238
239
240
241
242 /*
243 * function: w_write (function_write)
244 * purpose: write buffer to a descriptor.
245 * return: bytes written
246 */
247 ssize_t
248 w_write(unsigned int fd, const void *vbuf)
249 {
250 ssize_t nbytes;
251
252 /* send data. disable signals are do not wait */
253 nbytes = send(fd, vbuf + buf_counter[fd], buf_size[fd] - buf_counter[fd], MSG_DONTWAIT | MSG_NOSIGNAL);
254
255 /* check if send returned an error */
256 if (nbytes == -1)
257 {
258 /* ignore EAGAIN */
259 if (errno == EAGAIN)
260 {
261 if(DEBUG > 2)
262 logmessage("DEBUG: fd: %d write(): must try again after %d bytes (EAGAIN)\n", fd, nbytes);
263
264 return nbytes;
265 }
266
267 /* something bad happened */
268 if (DEBUG > 2)
269 logmessage("DEBUG: fd: %d connection problem during write: %s\n", fd, strerror(errno));
270
271 return -1;
272 }
273
274 /* EOF was reached if n == 0 */
275 if (nbytes == 0)
276 {
277 if (DEBUG > 2)
278 logmessage("DEBUG: fd: %d connection got an EOF during write after %d bytes\n", fd, nbytes);
279
280 return -1;
281 }
282
283 /* increment written buffer counter */
284 buf_counter[fd] += nbytes;
285
286 if (DEBUG > 2)
287 logmessage("DEBUG: fd: %d returning after %d bytes of data written\n", fd, nbytes);
288
289 /* check if buffer has been written */
290 if (buf_counter[fd] == buf_size[fd])
291 return -2;
292
293 return nbytes;
294 }
295
296
297
298
299 /*
300 * function: w_close (function_close)
301 * purpose: close a file descriptor
302 */
303 void
304 w_close(unsigned int fd)
305 {
306 if(DEBUG > 2)
307 logmessage("DEBUG: fd: %d shutting down fd %d\n", fd, fd);
308
309 /* shut down connection */
310 if (shutdown(fd, SHUT_RDWR) == -1)
311 logmessage("shutdown(%d): %s\n", fd, strerror(errno));
312
313 /* close a file descriptor */
314 if (close(fd) == -1)
315 logmessage("close(%d): %s\n", fd, strerror(errno));
316 }
317
318
319
320 /*
321 * function: w_tcp_conn_acl
322 * purpose: check if connecting host is allowed
323 * return: 0=allow, -1=disallow
324 */
325 int
326 w_tcp_conn_acl (const char *host)
327 {
328
329 char *p, range[strlen(CONN_ACL)];
330 unsigned long ip = inet_addr (host);
331 signed int xi;
332
333 strcpy(range, CONN_ACL); /* tmp buffer */
334 for( xi=strlen(range) ; xi >= 0 ; xi--)
335 {
336 p = range + xi; /* cycle backwards */
337 if((range[xi] == ' ') || (range[xi] == ',') || (range == p))
338 { /* delimiter */
339 if(range == p)
340 p = range + xi;
341 else
342 p = range + xi + 1;
343 if((p[strlen(p)-1] == ' ') || (p[strlen(p)-1] == ','))
344 p[strlen(p)-1] = 0x00; /* chomp trailing char */
345
346 if(cidr_ip_match(ip, p) == 1)
347 return (1); /* pass */
348 *p = 0x00; /* chomp old match */
349 }
350 }
351
352 return (-1); /* fail */
353 }
354
355
356
357 /*
358 * function: w_socket (wrapper_socket)
359 * purpose:
360 * return: file descriptor
361 */
362 int
363 w_socket(int family, int type, int protocol)
364 {
365 int n;
366
367 /* create an endpoint for communication */
368 if ((n = socket(family, type, protocol)) < 0)
369 {
370 logmessage("fatal: socket(): %s\n", strerror(errno));
371 exit(-1);
372 }
373
374 return (n);
375 }
376
377
378
379 /*
380 * function: w_socket (wrapper_socket)
381 * purpose:
382 * return: file descriptor
383 */
384 const char *
385 w_inet_ntop(int family, const void *addrptr, char *strptr, size_t len)
386 {
387 const char *ptr;
388
389 if (strptr == NULL) /* check for old code */
390 {
391 logmessage("fatal: NULL 3rd argument to w_inet_ntop");
392 exit(-1);
393 }
394
395 if ((ptr=inet_ntop(family, addrptr, strptr, len)) == NULL)
396 {
397 logmessage("fatal: inet_ntop(): %s\n", strerror(errno));
398 exit(-1);
399 }
400
401 return(ptr);
402 }
403
404
405
406
407 /*
408 * function: w_fork (wrapper_fork)
409 * purpose: background process
410 * return: pid
411 */
412 pid_t
413 w_fork(void)
414 {
415 pid_t pid;
416
417 if ((pid = fork()) == -1)
418 {
419 logmessage("fatal: fork(): %s\n", strerror(errno));
420 exit(-1);
421 }
422
423 return (pid);
424 }
425
426
427
428
429 /*
430 * function: daemon
431 * purpose: backgroup processes
432 * return: status
433 */
434 int
435 daemonize(int nochdir, int noclose)
436 {
437 unsigned int i;
438 pid_t pid;
439
440 if((pid=w_fork()) < 0)
441 return (-1);
442 else if(pid)
443 _exit(0); /* parent terminates */
444
445 /* child 1 continues */
446 if(setsid() < 0) /* become session leader */
447 return (-1);
448
449 if((pid=w_fork()) < 0)
450 return (-1);
451 else if(pid)
452 _exit(0); /* child 1 terminates */
453
454 /* child 2 continues */
455 if(nochdir)
456 chdir("/"); /* change working directory */
457
458 /* close off all file descriptors */
459 if(noclose)
460 for(i=0;i<64;i++)
461 close(i);
462
463 /* redirect stdin, stdout and stderr to /dev/null */
464 open("/dev/null", O_RDONLY);
465 open("/dev/null", O_RDWR);
466 open("/dev/null", O_RDWR);
467
468 return (0);
469 }
470
471 /* EOF */
472