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