xref: /openbsd-src/sbin/isakmpd/util.c (revision 3a3fbb3f2e2521ab7c4a56b7ff7462ebd9095ec5)
1 /*	$OpenBSD: util.c,v 1.23 2001/10/26 13:29:26 ho Exp $	*/
2 /*	$EOM: util.c,v 1.23 2000/11/23 12:22:08 niklas Exp $	*/
3 
4 /*
5  * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist.  All rights reserved.
6  * Copyright (c) 2000, 2001 H�kan Olsson.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by Ericsson Radio Systems.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * This code was written under funding by Ericsson Radio Systems.
36  */
37 
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <sys/stat.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
43 #include <limits.h>
44 #include <netdb.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <errno.h>
49 
50 #include "sysdep.h"
51 
52 #include "log.h"
53 #include "message.h"
54 #include "sysdep.h"
55 #include "transport.h"
56 #include "util.h"
57 
58 /*
59  * Set if -N is given, allowing name lookups to be done, possibly stalling
60  * the daemon for quite a while.
61  */
62 int allow_name_lookups = 0;
63 
64 /*
65  * This is set to true in case of regression-test mode, when it will
66  * cause predictable random numbers be generated.
67  */
68 int regrand = 0;
69 
70 /*
71  * If in regression-test mode, this is the seed used.
72  */
73 unsigned long seed;
74 
75 /*
76  * XXX These might be turned into inlines or macros, maybe even
77  * machine-dependent ones, for performance reasons.
78  */
79 u_int16_t
80 decode_16 (u_int8_t *cp)
81 {
82   return cp[0] << 8 | cp[1];
83 }
84 
85 u_int32_t
86 decode_32 (u_int8_t *cp)
87 {
88   return cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3];
89 }
90 
91 u_int64_t
92 decode_64 (u_int8_t *cp)
93 {
94   return (u_int64_t)cp[0] << 56 | (u_int64_t)cp[1] << 48
95     | (u_int64_t)cp[2] << 40 | (u_int64_t)cp[3] << 32
96     | cp[4] << 24 | cp[5] << 16 | cp[6] << 8 | cp[7];
97 }
98 
99 #if 0
100 /*
101  * XXX I severly doubt that we will need this.  IPv6 does not have the legacy
102  * of representation in host byte order, AFAIK.
103  */
104 
105 void
106 decode_128 (u_int8_t *cp, u_int8_t *cpp)
107 {
108 #if BYTE_ORDER == LITTLE_ENDIAN
109   int i;
110 
111   for (i = 0; i < 16; i++)
112     cpp[i] = cp[15 - i];
113 #elif BYTE_ORDER == BIG_ENDIAN
114   bcopy (cp, cpp, 16);
115 #else
116 #error "Byte order unknown!"
117 #endif
118 }
119 #endif
120 
121 void
122 encode_16 (u_int8_t *cp, u_int16_t x)
123 {
124   *cp++ = x >> 8;
125   *cp = x & 0xff;
126 }
127 
128 void
129 encode_32 (u_int8_t *cp, u_int32_t x)
130 {
131   *cp++ = x >> 24;
132   *cp++ = (x >> 16) & 0xff;
133   *cp++ = (x >> 8) & 0xff;
134   *cp = x & 0xff;
135 }
136 
137 void
138 encode_64 (u_int8_t *cp, u_int64_t x)
139 {
140   *cp++ = x >> 56;
141   *cp++ = (x >> 48) & 0xff;
142   *cp++ = (x >> 40) & 0xff;
143   *cp++ = (x >> 32) & 0xff;
144   *cp++ = (x >> 24) & 0xff;
145   *cp++ = (x >> 16) & 0xff;
146   *cp++ = (x >> 8) & 0xff;
147   *cp = x & 0xff;
148 }
149 
150 #if 0
151 /*
152  * XXX I severly doubt that we will need this.  IPv6 does not have the legacy
153  * of representation in host byte order, AFAIK.
154  */
155 
156 void
157 encode_128 (u_int8_t *cp, u_int8_t *cpp)
158 {
159   decode_128 (cpp, cp);
160 }
161 #endif
162 
163 /* Check a buffer for all zeroes.  */
164 int
165 zero_test (const u_int8_t *p, size_t sz)
166 {
167   while (sz-- > 0)
168     if (*p++ != 0)
169       return 0;
170   return 1;
171 }
172 
173 /* Check a buffer for all ones.  */
174 int
175 ones_test (const u_int8_t *p, size_t sz)
176 {
177   while (sz-- > 0)
178     if (*p++ != 0xff)
179       return 0;
180   return 1;
181 }
182 
183 /*
184  * Generate a random data, len bytes long.
185  */
186 u_int8_t *
187 getrandom (u_int8_t *buf, size_t len)
188 {
189   u_int32_t tmp = 0;
190   int i;
191 
192   for (i = 0; i < len; i++)
193     {
194       if (i % sizeof tmp == 0)
195 	tmp = sysdep_random ();
196 
197       buf[i] = tmp & 0xff;
198       tmp >>= 8;
199     }
200 
201   return buf;
202 }
203 
204 static __inline int
205 hex2nibble (char c)
206 {
207   if (c >= '0' && c <= '9')
208     return c - '0';
209   if (c >= 'a' && c <= 'f')
210     return c - 'a' + 10;
211   if (c >= 'A' && c <= 'F')
212     return c - 'A' + 10;
213   return -1;
214 }
215 
216 /*
217  * Convert hexadecimal string in S to raw binary buffer at BUF sized SZ
218  * bytes.  Return 0 if everything is OK, -1 otherwise.
219  */
220 int
221 hex2raw (char *s, u_int8_t *buf, size_t sz)
222 {
223   char *p;
224   u_int8_t *bp;
225   int tmp;
226 
227   if (strlen (s) > sz * 2)
228     return -1;
229   for (p = s + strlen (s) - 1, bp = &buf[sz - 1]; bp >= buf; bp--)
230     {
231       *bp = 0;
232       if (p >= s)
233 	{
234 	  tmp = hex2nibble (*p--);
235 	  if (tmp == -1)
236 	    return -1;
237 	  *bp = tmp;
238 	}
239       if (p >= s)
240 	{
241 	  tmp = hex2nibble (*p--);
242 	  if (tmp == -1)
243 	    return -1;
244 	  *bp |= tmp << 4;
245 	}
246     }
247   return 0;
248 }
249 
250 int
251 text2sockaddr (char *address, char *port, struct sockaddr **sa)
252 {
253 #ifdef HAVE_GETNAMEINFO
254   struct addrinfo *ai, hints;
255 
256   memset (&hints, 0, sizeof hints);
257   if (!allow_name_lookups)
258     hints.ai_flags = AI_NUMERICHOST;
259   hints.ai_family = PF_UNSPEC;
260   hints.ai_socktype = SOCK_DGRAM;
261   hints.ai_protocol = IPPROTO_UDP;
262 
263   if (getaddrinfo (address, port, &hints, &ai))
264     return -1;
265 
266   *sa = malloc (sysdep_sa_len (ai->ai_addr));
267   if (!sa)
268     return -1;
269 
270   memcpy (*sa, ai->ai_addr, sysdep_sa_len (ai->ai_addr));
271   freeaddrinfo (ai);
272   return 0;
273 #else
274   int af = strchr (address, ':') != NULL ? AF_INET6 : AF_INET;
275   size_t sz = af == AF_INET
276     ? sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6);
277   long lport;
278   struct servent *sp;
279   char *ep;
280 
281   *sa = calloc (1, sz);
282   if (!*sa)
283     return -1;
284 
285 #ifndef USE_OLD_SOCKADDR
286   (*sa)->sa_len = sz;
287 #endif
288   (*sa)->sa_family = af;
289   if (inet_pton (af, address, sockaddr_addrdata (*sa)) != 1)
290     {
291       free (*sa);
292       return -1;
293     }
294   sp = getservbyname (port, "udp");
295   if (!sp)
296     {
297       lport = strtol (port, &ep, 10);
298       if (ep == port || lport < 0 || lport > USHRT_MAX)
299 	{
300 	  free (*sa);
301 	  return -1;
302 	}
303       lport = htons (lport);
304     }
305   else
306     lport = sp->s_port;
307   if ((*sa)->sa_family == AF_INET)
308     ((struct sockaddr_in *)*sa)->sin_port = lport;
309   else
310     ((struct sockaddr_in6 *)*sa)->sin6_port = lport;
311   return 0;
312 #endif
313 }
314 
315 /*
316  * Convert a sockaddr to text. With zflag non-zero fill out with zeroes,
317  * i.e 10.0.0.10 --> "010.000.000.010"
318  */
319 int
320 sockaddr2text (struct sockaddr *sa, char **address, int zflag)
321 {
322   char buf[NI_MAXHOST];
323   char *token, *bstart, *ep;
324   int addrlen;
325   long val;
326   int i, j;
327 
328 #ifdef HAVE_GETNAMEINFO
329   if (getnameinfo (sa, sysdep_sa_len (sa), buf, sizeof buf, 0, 0,
330 		   allow_name_lookups ? 0 : NI_NUMERICHOST))
331     return -1;
332 #else
333   switch (sa->sa_family)
334     {
335     case AF_INET:
336     case AF_INET6:
337       if (inet_ntop (sa->sa_family, sa->sa_data, buf, NI_MAXHOST - 1) == NULL)
338 	{
339 	  log_error ("sockaddr2text: inet_ntop (%d, %p, %p, %d) failed",
340 		     sa->sa_family, sa->sa_data, buf, NI_MAXHOST - 1);
341 	  return -1;
342 	}
343       buf[NI_MAXHOST - 1] = '\0';
344       break;
345 
346     default:
347       log_print ("sockaddr2text: unsupported protocol family %d\n",
348 		  sa->sa_family);
349       return -1;
350     }
351 #endif
352 
353   if (zflag == 0)
354     {
355       *address = malloc (strlen (buf) + 1);
356       if (!*address)
357 	return -1;
358       strcpy (*address, buf);
359     }
360   else
361     switch (sa->sa_family)
362       {
363       case AF_INET:
364 	addrlen = sizeof "000.000.000.000";
365 	*address = malloc (addrlen);
366 	if (!*address)
367 	  return -1;
368 	buf[addrlen] = '\0';
369 	bstart = buf;
370 	**address = '\0';
371 	while ((token = strsep (&bstart, ".")) != NULL)
372 	  {
373 	    if (strlen (*address) > 12)
374 	      {
375 		free (*address);
376 		return -1;
377 	      }
378 	    val = strtol (token, &ep, 10);
379 	    if (ep == token || val < 0 || val > UCHAR_MAX)
380 	      {
381 		free (*address);
382 		return -1;
383 	      }
384 	    sprintf (*address + strlen (*address), "%03ld", val);
385 	    if (bstart)
386 	      strcat (*address + strlen (*address), ".");
387 	  }
388 	break;
389 
390       case AF_INET6:
391 	/*
392 	 * XXX In the algorithm below there are some magic numbers we
393 	 * probably could give explaining names.
394 	 */
395 	addrlen = sizeof "0000:0000:0000:0000:0000:0000:0000:0000";
396 	*address = malloc (addrlen);
397 	if (!*address)
398 	  return -1;
399 
400 	for (i = 0, j = 0; i < 8; i++)
401 	  j += sprintf ((*address) + j, "%02x%02x:",
402 			((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[2 * i],
403 			((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[2 * i + 1]);
404 	(*address)[j - 1] = '\0';
405 	break;
406 
407       default:
408 	strcpy (*address, "<error>");
409       }
410 
411   return 0;
412 }
413 
414 /*
415  * sockaddr_addrlen and sockaddr_addrdata return the relevant sockaddr info
416  * depending on address family.  Useful to keep other code shorter(/clearer?).
417  */
418 int
419 sockaddr_addrlen (struct sockaddr *sa)
420 {
421   switch (sa->sa_family)
422     {
423     case AF_INET6:
424       return sizeof ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr;
425     case AF_INET:
426       return sizeof ((struct sockaddr_in *)sa)->sin_addr.s_addr;
427     default:
428       log_print ("sockaddr_addrlen: unsupported protocol family %d",
429 		 sa->sa_family);
430       return 0;
431     }
432 }
433 
434 u_int8_t *
435 sockaddr_addrdata (struct sockaddr *sa)
436 {
437   switch (sa->sa_family)
438     {
439     case AF_INET6:
440       return (u_int8_t *)&((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr;
441     case AF_INET:
442       return (u_int8_t *)&((struct sockaddr_in *)sa)->sin_addr.s_addr;
443     default:
444       log_print ("sockaddr_addrdata: unsupported protocol family %d",
445 		 sa->sa_family);
446       return 0;
447     }
448 }
449 
450 /*
451  * Convert network address to text. The network address does not need
452  * to be properly aligned.
453  */
454 void
455 util_ntoa (char **buf, int af, u_int8_t *addr)
456 {
457   struct sockaddr_storage from;
458   struct sockaddr *sfrom = (struct sockaddr *)&from;
459   socklen_t fromlen = sizeof from;
460 
461   memset (&from, 0, fromlen);
462   sfrom->sa_family = af;
463 #ifndef USE_OLD_SOCKADDR
464   sfrom->sa_len = sysdep_sa_len (sfrom);
465 #endif
466   memcpy (sockaddr_addrdata (sfrom), addr, sockaddr_addrlen (sfrom));
467 
468   if (sockaddr2text (sfrom, buf, 0))
469     {
470       log_print ("util_ntoa: "
471 		 "could not make printable address out of sockaddr %p", sfrom);
472       *buf = 0;
473     }
474 }
475 
476 /*
477  * Perform sanity check on files containing secret information.
478  * Returns -1 on failure, 0 otherwise.
479  * Also, if FILE_SIZE is a not a null pointer, store file size here.
480  */
481 int
482 check_file_secrecy (char *name, off_t *file_size)
483 {
484   struct stat st;
485 
486   if (stat (name, &st) == -1)
487     {
488       log_error ("check_file_secrecy: stat (\"%s\") failed", name);
489       return -1;
490     }
491   if (st.st_uid != geteuid () && st.st_uid != getuid ())
492     {
493       log_print ("check_file_secrecy: "
494 		 "not loading %s - file owner is not process user", name);
495       errno = EPERM;
496       return -1;
497     }
498   if ((st.st_mode & (S_IRWXG | S_IRWXO)) != 0)
499     {
500       log_print ("conf_file_secrecy: not loading %s - too open permissions",
501 		 name);
502       errno = EPERM;
503       return -1;
504     }
505 
506   if (file_size)
507     *file_size = st.st_size;
508 
509   return 0;
510 }
511