Revert Jim's earlier "fix" :)
[asterisk/asterisk.git] / acl.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Various sorts of access control
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/time.h>
18 #include <signal.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <asterisk/acl.h>
22 #include <asterisk/logger.h>
23 #include <asterisk/channel.h>
24 #include <asterisk/utils.h>
25 #include <asterisk/lock.h>
26 #include <asterisk/srv.h>
27 #include <arpa/inet.h>
28 #include <sys/socket.h>
29 #include <netdb.h>
30 #include <net/if.h>
31 #include <netinet/in_systm.h>
32 #include <netinet/ip.h>
33 #include <sys/ioctl.h>
34 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
35 #include <fcntl.h>
36 #include <net/route.h>
37
38 AST_MUTEX_DEFINE_STATIC(routeseq_lock);
39 #endif
40
41 #if defined (SOLARIS)
42 #include <sys/sockio.h>
43 #endif
44
45
46
47 struct ast_ha {
48         /* Host access rule */
49         struct in_addr netaddr;
50         struct in_addr netmask;
51         int sense;
52         struct ast_ha *next;
53 };
54
55 /* Default IP - if not otherwise set, don't breathe garbage */
56 static struct in_addr __ourip = { 0x00000000 };
57
58 struct my_ifreq {
59         char ifrn_name[IFNAMSIZ];       /* Interface name, e.g. "eth0", "ppp0", etc.  */
60         struct sockaddr_in ifru_addr;
61 };
62
63 /* Free HA structure */
64 void ast_free_ha(struct ast_ha *ha)
65 {
66         struct ast_ha *hal;
67         while(ha) {
68                 hal = ha;
69                 ha = ha->next;
70                 free(hal);
71         }
72 }
73
74 /* Copy HA structure */
75 static void ast_copy_ha(struct ast_ha *from, struct ast_ha *to)
76 {
77         memcpy(&to->netaddr, &from->netaddr, sizeof(from->netaddr));
78         memcpy(&to->netmask, &from->netmask, sizeof(from->netmask));
79         to->sense = from->sense;
80 }
81
82 /* Create duplicate of ha structure */
83 static struct ast_ha *ast_duplicate_ha(struct ast_ha *original)
84 {
85         struct ast_ha *new_ha = malloc(sizeof(struct ast_ha));
86
87         /* Copy from original to new object */
88         ast_copy_ha(original, new_ha); 
89
90         return(new_ha);
91
92 }
93
94 /* Create duplicate HA link list */
95 /*  Used in chan_sip2 templates */
96 struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original)
97 {
98         struct ast_ha *start=original;
99         struct ast_ha *ret = NULL;
100         struct ast_ha *link,*prev=NULL;
101
102         while(start) {
103                 link = ast_duplicate_ha(start);  /* Create copy of this object */
104                 if (prev)
105                         prev->next = link;              /* Link previous to this object */
106
107                 if (!ret) 
108                         ret = link;             /* Save starting point */
109
110                 start = start->next;            /* Go to next object */
111                 prev = link;                    /* Save pointer to this object */
112         }
113         return (ret);                           /* Return start of list */
114 }
115
116 struct ast_ha *ast_append_ha(char *sense, char *stuff, struct ast_ha *path)
117 {
118         struct ast_ha *ha = malloc(sizeof(struct ast_ha));
119         char *nm="255.255.255.255";
120         char tmp[256] = "";
121         struct ast_ha *prev = NULL;
122         struct ast_ha *ret;
123         int x,z;
124         unsigned int y;
125         ret = path;
126         while(path) {
127                 prev = path;
128                 path = path->next;
129         }
130         if (ha) {
131                 strncpy(tmp, stuff, sizeof(tmp) - 1);
132                 nm = strchr(tmp, '/');
133                 if (!nm)
134                         nm = "255.255.255.255";
135                 else {
136                         *nm = '\0';
137                         nm++;
138                 }
139                 if (!strchr(nm, '.')) {
140                         if ((sscanf(nm, "%i", &x) == 1) && (x >= 0) && (x <= 32)) {
141                                 y = 0;
142                                 for (z=0;z<x;z++) {
143                                         y >>= 1;
144                                         y |= 0x80000000;
145                                 }
146                                 ha->netmask.s_addr = htonl(y);
147                         }
148                 } else if (!inet_aton(nm, &ha->netmask)) {
149                         ast_log(LOG_WARNING, "%s not a valid netmask\n", nm);
150                         free(ha);
151                         return path;
152                 }
153                 if (!inet_aton(tmp, &ha->netaddr)) {
154                         ast_log(LOG_WARNING, "%s not a valid IP\n", tmp);
155                         free(ha);
156                         return path;
157                 }
158                 ha->netaddr.s_addr &= ha->netmask.s_addr;
159                 if (!strncasecmp(sense, "p", 1)) {
160                         ha->sense = AST_SENSE_ALLOW;
161                 } else {
162                         ha->sense = AST_SENSE_DENY;
163                 }
164                 ha->next = NULL;
165                 if (prev)
166                         prev->next = ha;
167                 else
168                         ret = ha;
169         }
170         ast_log(LOG_DEBUG, "%s/%s appended to acl for peer\n",stuff, nm);
171         return ret;
172 }
173
174 int ast_apply_ha(struct ast_ha *ha, struct sockaddr_in *sin)
175 {
176         /* Start optimistic */
177         int res = AST_SENSE_ALLOW;
178         while(ha) {
179                 char iabuf[INET_ADDRSTRLEN];
180                 char iabuf2[INET_ADDRSTRLEN];
181                 /* DEBUG */
182                 ast_log(LOG_DEBUG,
183                         "##### Testing %s with %s\n",
184                         ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr),
185                         ast_inet_ntoa(iabuf2, sizeof(iabuf2), ha->netaddr));
186                 /* For each rule, if this address and the netmask = the net address
187                    apply the current rule */
188                 if ((sin->sin_addr.s_addr & ha->netmask.s_addr) == (ha->netaddr.s_addr))
189                         res = ha->sense;
190                 ha = ha->next;
191         }
192         return res;
193 }
194
195 int ast_get_ip_or_srv(struct sockaddr_in *sin, const char *value, const char *service)
196 {
197         struct hostent *hp;
198         struct ast_hostent ahp;
199         char srv[256];
200         char host[256];
201         int tportno = ntohs(sin->sin_port);
202         if (service) {
203                 snprintf(srv, sizeof(srv), "%s.%s", service, value);
204                 if (ast_get_srv(NULL, host, sizeof(host), &tportno, srv) > 0) {
205                         sin->sin_port = htons(tportno);
206                         value = host;
207                 }
208         }
209         hp = ast_gethostbyname(value, &ahp);
210         if (hp) {
211                 memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
212         } else {
213                 ast_log(LOG_WARNING, "Unable to lookup '%s'\n", value);
214                 return -1;
215         }
216         return 0;
217 }
218
219 int ast_get_ip(struct sockaddr_in *sin, const char *value)
220 {
221         return ast_get_ip_or_srv(sin, value, NULL);
222 }
223
224 /* iface is the interface (e.g. eth0); address is the return value */
225 int ast_lookup_iface(char *iface, struct in_addr *address) {
226         int mysock, res = 0;
227         struct my_ifreq ifreq;
228
229         memset(&ifreq, 0, sizeof(ifreq));
230         strncpy(ifreq.ifrn_name,iface,sizeof(ifreq.ifrn_name) - 1);
231
232         mysock = socket(PF_INET,SOCK_DGRAM,IPPROTO_IP);
233         res = ioctl(mysock,SIOCGIFADDR,&ifreq);
234
235         close(mysock);
236         if (res < 0) {
237                 ast_log(LOG_WARNING, "Unable to get IP of %s: %s\n", iface, strerror(errno));
238                 memcpy((char *)address,(char *)&__ourip,sizeof(__ourip));
239                 return -1;
240         } else {
241                 memcpy((char *)address,(char *)&ifreq.ifru_addr.sin_addr,sizeof(ifreq.ifru_addr.sin_addr));
242                 return 0;
243         }
244 }
245
246 int ast_ouraddrfor(struct in_addr *them, struct in_addr *us)
247 {
248         int s;
249         struct sockaddr_in sin;
250         socklen_t slen;
251
252         s = socket(PF_INET, SOCK_DGRAM, 0);
253         if (s == -1) {
254                 ast_log(LOG_WARNING, "Cannot create socket\n");
255                 return -1;
256         }
257         sin.sin_family = AF_INET;
258         sin.sin_port = 5060;
259         sin.sin_addr = *them;
260         if (connect(s, (struct sockaddr *)&sin, sizeof(sin))) {
261                 ast_log(LOG_WARNING, "Cannot connect\n");
262                 close(s);
263                 return -1;
264         }
265         slen = sizeof(sin);
266         if (getsockname(s, (struct sockaddr *)&sin, &slen)) {
267                 ast_log(LOG_WARNING, "Cannot get socket name\n");
268                 close(s);
269                 return -1;
270         }
271         close(s);
272         *us = sin.sin_addr;
273         return 0;
274 }