chiark / gitweb /
add with-lock-ex to new chiark-utils-bin package
[chiark-utils.git] / cprogs / smtpallow.c
1 /*
2  * smtpallow.c - ld_preload for hacking with connect() !
3  *
4  * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
5  *
6  * This is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2,
9  * or (at your option) any later version.
10  *
11  * This is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this file; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include <syscall.h>
22 #include <sys/socketcall.h>
23 #include <netinet/in.h>
24 #include <string.h>
25
26 _syscall2(long,socketcall,int,call,unsigned long *,args);
27
28 int real_connect(int sockfd, const struct sockaddr *saddr, int addrlen)
29 {
30         unsigned long args[3];
31
32         args[0] = sockfd;
33         args[1] = (unsigned long)saddr;
34         args[2] = addrlen;
35         return socketcall(SYS_CONNECT, args);
36 }
37
38 int connect(int fd, const struct sockaddr *them_any, int addrlen) {
39   struct sockaddr_in *them= (struct sockaddr_in*)them_any;
40   int r,l,i;
41   struct sockaddr_in us;
42   
43   if (addrlen == sizeof(us) &&
44       them->sin_family == AF_INET &&
45       them->sin_port == htons(25)) {
46     memset(&us,0,sizeof(us));
47     us.sin_port= 0;
48     us.sin_family= AF_INET;
49     us.sin_addr.s_addr= INADDR_ANY;
50     r= getsockname(fd,(struct sockaddr*)&us,&l);
51     if (r<0 && errno != EINVAL) return r;
52     if (!ntohs(us.sin_port)) {
53       for (i=1023; i>0; i--) {
54         us.sin_port= htons(i);
55         if (!bind(fd,(struct sockaddr*)&us,sizeof(us))) break;
56         if (errno != EADDRINUSE) return -1;
57       }
58       if (!i) return -1;
59     } else if (r<0) return r;
60   }
61   return real_connect(fd,them_any,addrlen);
62 }