Revert "Revert "and added files""
[bcm963xx.git] / userapps / opensource / ipsec-tools / src / libipsec / ipsec_dump_policy.c
1 /* $Id: ipsec_dump_policy.c,v 1.7 2004/10/29 16:37:03 ludvigm Exp $ */
2
3 /*
4  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/socket.h>
39
40 #include <netinet/in.h>
41 #ifdef HAVE_NETINET6_IPSEC
42 #  include <netinet6/ipsec.h>
43 #else
44 #  include <netinet/ipsec.h>
45 #endif
46
47 #include <arpa/inet.h>
48
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <netdb.h>
53
54 #include "ipsec_strerror.h"
55 #include "libpfkey.h"
56
57 static const char *ipsp_dir_strs[] = {
58         "any", "in", "out", "fwd"
59 };
60
61 static const char *ipsp_policy_strs[] = {
62         "discard", "none", "ipsec", "entrust", "bypass",
63 };
64
65 static char *ipsec_dump_ipsecrequest __P((char *, size_t,
66         struct sadb_x_ipsecrequest *, size_t));
67 static int set_addresses __P((char *, size_t, struct sockaddr *,
68         struct sockaddr *));
69 static char *set_address __P((char *, size_t, struct sockaddr *));
70
71 /*
72  * policy is sadb_x_policy buffer.
73  * Must call free() later.
74  * When delimiter == NULL, alternatively ' '(space) is applied.
75  */
76 char *
77 ipsec_dump_policy(policy, delimiter)
78         caddr_t policy;
79         char *delimiter;
80 {
81         struct sadb_x_policy *xpl = (struct sadb_x_policy *)policy;
82         struct sadb_x_ipsecrequest *xisr;
83         size_t off, buflen;
84         char *buf;
85         char isrbuf[1024];
86         char *newbuf;
87
88 #ifdef HAVE_PFKEY_POLICY_PRIORITY
89         int32_t priority_offset;
90         char *priority_str;
91         char operator;
92 #endif
93
94         /* sanity check */
95         if (policy == NULL)
96                 return NULL;
97         if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) {
98                 __ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
99                 return NULL;
100         }
101
102         /* set delimiter */
103         if (delimiter == NULL)
104                 delimiter = " ";
105
106 #ifdef HAVE_PFKEY_POLICY_PRIORITY
107         if (xpl->sadb_x_policy_priority == 0)
108         {
109                 priority_offset = 0;
110                 priority_str = "";
111         }
112         /* find which constant the priority is closest to */
113         else if (xpl->sadb_x_policy_priority < 
114                  (u_int32_t) (PRIORITY_DEFAULT / 4) * 3)
115         {
116                 priority_offset = xpl->sadb_x_policy_priority - PRIORITY_HIGH;
117                 priority_str = "prio high";
118         }
119         else if (xpl->sadb_x_policy_priority >= 
120                  (u_int32_t) (PRIORITY_DEFAULT / 4) * 3 &&
121                  xpl->sadb_x_policy_priority < 
122                  (u_int32_t) (PRIORITY_DEFAULT / 4) * 5)
123         {
124                 priority_offset = xpl->sadb_x_policy_priority - PRIORITY_DEFAULT;
125                 priority_str = "prio def";
126         }
127         else
128         {
129                 priority_offset = xpl->sadb_x_policy_priority - PRIORITY_LOW;
130                 priority_str = "prio low";
131         }
132
133         /* fix sign to match the way it is input */
134         priority_offset *= -1;
135         if (priority_offset < 0)
136         {
137                 operator = '-';
138                 priority_offset *= -1;
139         }
140         else
141         {
142                 operator = '+';
143         }
144 #endif
145         
146         switch (xpl->sadb_x_policy_dir) {
147         case IPSEC_DIR_ANY:
148         case IPSEC_DIR_INBOUND:
149         case IPSEC_DIR_OUTBOUND:
150 #ifdef HAVE_POLICY_FWD
151         case IPSEC_DIR_FWD:
152 #endif
153                 break;
154         default:
155                 __ipsec_errcode = EIPSEC_INVAL_DIR;
156                 return NULL;
157         }
158
159         switch (xpl->sadb_x_policy_type) {
160         case IPSEC_POLICY_DISCARD:
161         case IPSEC_POLICY_NONE:
162         case IPSEC_POLICY_IPSEC:
163         case IPSEC_POLICY_BYPASS:
164         case IPSEC_POLICY_ENTRUST:
165                 break;
166         default:
167                 __ipsec_errcode = EIPSEC_INVAL_POLICY;
168                 return NULL;
169         }
170
171         buflen = strlen(ipsp_dir_strs[xpl->sadb_x_policy_dir])
172                 + 1     /* space */
173 #ifdef HAVE_PFKEY_POLICY_PRIORITY
174                 + strlen(priority_str)
175                 + ((priority_offset != 0) ? 13 : 0) /* [space operator space int] */
176                 + ((strlen(priority_str) != 0) ? 1 : 0) /* space */
177 #endif
178                 + strlen(ipsp_policy_strs[xpl->sadb_x_policy_type])
179                 + 1;    /* NUL */
180
181         if ((buf = malloc(buflen)) == NULL) {
182                 __ipsec_errcode = EIPSEC_NO_BUFS;
183                 return NULL;
184         }
185 #ifdef HAVE_PFKEY_POLICY_PRIORITY
186         if (priority_offset != 0)
187         {
188                 snprintf(buf, buflen, "%s %s %c %u %s", 
189                 ipsp_dir_strs[xpl->sadb_x_policy_dir], priority_str, operator, 
190                         priority_offset, ipsp_policy_strs[xpl->sadb_x_policy_type]);
191         }
192         else if (strlen (priority_str) != 0)
193         {
194                 snprintf(buf, buflen, "%s %s %s", 
195                 ipsp_dir_strs[xpl->sadb_x_policy_dir], priority_str, 
196                         ipsp_policy_strs[xpl->sadb_x_policy_type]);
197         }
198         else
199         {
200                 snprintf(buf, buflen, "%s %s", 
201                 ipsp_dir_strs[xpl->sadb_x_policy_dir],
202                         ipsp_policy_strs[xpl->sadb_x_policy_type]);
203         }
204 #else
205         snprintf(buf, buflen, "%s %s", ipsp_dir_strs[xpl->sadb_x_policy_dir],
206             ipsp_policy_strs[xpl->sadb_x_policy_type]);
207 #endif
208
209         if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) {
210                 __ipsec_errcode = EIPSEC_NO_ERROR;
211                 return buf;
212         }
213
214         /* count length of buffer for use */
215         off = sizeof(*xpl);
216         while (off < PFKEY_EXTLEN(xpl)) {
217                 xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xpl + off);
218                 off += xisr->sadb_x_ipsecrequest_len;
219         }
220
221         /* validity check */
222         if (off != PFKEY_EXTLEN(xpl)) {
223                 __ipsec_errcode = EIPSEC_INVAL_SADBMSG;
224                 free(buf);
225                 return NULL;
226         }
227
228         off = sizeof(*xpl);
229         while (off < PFKEY_EXTLEN(xpl)) {
230                 int offset;
231                 xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xpl + off);
232
233                 if (ipsec_dump_ipsecrequest(isrbuf, sizeof(isrbuf), xisr,
234                     PFKEY_EXTLEN(xpl) - off) == NULL) {
235                         free(buf);
236                         return NULL;
237                 }
238
239                 offset = strlen(buf);
240                 buflen = offset + strlen(delimiter) + strlen(isrbuf) + 1;
241                 newbuf = (char *)realloc(buf, buflen);
242                 if (newbuf == NULL) {
243                         __ipsec_errcode = EIPSEC_NO_BUFS;
244                         free(buf);
245                         return NULL;
246                 }
247                 buf = newbuf;
248                 snprintf(buf+offset, buflen-offset, "%s%s", delimiter, isrbuf);
249
250                 off += xisr->sadb_x_ipsecrequest_len;
251         }
252
253         __ipsec_errcode = EIPSEC_NO_ERROR;
254         return buf;
255 }
256
257 static char *
258 ipsec_dump_ipsecrequest(buf, len, xisr, bound)
259         char *buf;
260         size_t len;
261         struct sadb_x_ipsecrequest *xisr;
262         size_t bound;   /* boundary */
263 {
264         const char *proto, *mode, *level;
265         char abuf[NI_MAXHOST * 2 + 2];
266
267         if (xisr->sadb_x_ipsecrequest_len > bound) {
268                 __ipsec_errcode = EIPSEC_INVAL_PROTO;
269                 return NULL;
270         }
271
272         switch (xisr->sadb_x_ipsecrequest_proto) {
273         case IPPROTO_ESP:
274                 proto = "esp";
275                 break;
276         case IPPROTO_AH:
277                 proto = "ah";
278                 break;
279         case IPPROTO_IPCOMP:
280                 proto = "ipcomp";
281                 break;
282         default:
283                 __ipsec_errcode = EIPSEC_INVAL_PROTO;
284                 return NULL;
285         }
286
287         switch (xisr->sadb_x_ipsecrequest_mode) {
288         case IPSEC_MODE_ANY:
289                 mode = "any";
290                 break;
291         case IPSEC_MODE_TRANSPORT:
292                 mode = "transport";
293                 break;
294         case IPSEC_MODE_TUNNEL:
295                 mode = "tunnel";
296                 break;
297         default:
298                 __ipsec_errcode = EIPSEC_INVAL_MODE;
299                 return NULL;
300         }
301
302         abuf[0] = '\0';
303         if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) {
304                 struct sockaddr *sa1, *sa2;
305                 caddr_t p;
306
307                 p = (caddr_t)(xisr + 1);
308                 sa1 = (struct sockaddr *)p;
309                 sa2 = (struct sockaddr *)(p + sysdep_sa_len(sa1));
310                 if (sizeof(*xisr) + sysdep_sa_len(sa1) + sysdep_sa_len(sa2) !=
311                     xisr->sadb_x_ipsecrequest_len) {
312                         __ipsec_errcode = EIPSEC_INVAL_ADDRESS;
313                         return NULL;
314                 }
315                 if (set_addresses(abuf, sizeof(abuf), sa1, sa2) != 0) {
316                         __ipsec_errcode = EIPSEC_INVAL_ADDRESS;
317                         return NULL;
318                 }
319         }
320
321         switch (xisr->sadb_x_ipsecrequest_level) {
322         case IPSEC_LEVEL_DEFAULT:
323                 level = "default";
324                 break;
325         case IPSEC_LEVEL_USE:
326                 level = "use";
327                 break;
328         case IPSEC_LEVEL_REQUIRE:
329                 level = "require";
330                 break;
331         case IPSEC_LEVEL_UNIQUE:
332                 level = "unique";
333                 break;
334         default:
335                 __ipsec_errcode = EIPSEC_INVAL_LEVEL;
336                 return NULL;
337         }
338
339         if (xisr->sadb_x_ipsecrequest_reqid == 0)
340                 snprintf(buf, len, "%s/%s/%s/%s", proto, mode, abuf, level);
341         else {
342                 int ch;
343
344                 if (xisr->sadb_x_ipsecrequest_reqid > IPSEC_MANUAL_REQID_MAX)
345                         ch = '#';
346                 else
347                         ch = ':';
348                 snprintf(buf, len, "%s/%s/%s/%s%c%u", proto, mode, abuf, level,
349                     ch, xisr->sadb_x_ipsecrequest_reqid);
350         }
351
352         return buf;
353 }
354
355 static int
356 set_addresses(buf, len, sa1, sa2)
357         char *buf;
358         size_t len;
359         struct sockaddr *sa1;
360         struct sockaddr *sa2;
361 {
362         char tmp1[NI_MAXHOST], tmp2[NI_MAXHOST];
363
364         if (set_address(tmp1, sizeof(tmp1), sa1) == NULL ||
365             set_address(tmp2, sizeof(tmp2), sa2) == NULL)
366                 return -1;
367         if (strlen(tmp1) + 1 + strlen(tmp2) + 1 > len)
368                 return -1;
369         snprintf(buf, len, "%s-%s", tmp1, tmp2);
370         return 0;
371 }
372
373 static char *
374 set_address(buf, len, sa)
375         char *buf;
376         size_t len;
377         struct sockaddr *sa;
378 {
379         const int niflags = NI_NUMERICHOST;
380
381         if (len < 1)
382                 return NULL;
383         buf[0] = '\0';
384         if (getnameinfo(sa, sysdep_sa_len(sa), buf, len, NULL, 0, niflags) != 0)
385                 return NULL;
386         return buf;
387 }