xref: /openbsd-src/sbin/isakmpd/util.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: util.c,v 1.21 2001/07/03 23:39:01 angelos 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 (ai->ai_addr->sa_len);
267   if (!sa)
268     return -1;
269 
270   memcpy (*sa, ai->ai_addr, ai->ai_addr->sa_len);
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   (*sa)->sa_len = sz;
286   (*sa)->sa_family = af;
287   if (inet_pton (af, address, sockaddr_data (*sa)) != 1)
288     {
289       free (*sa);
290       return -1;
291     }
292   sp = getservbyname (port, "udp");
293   if (!sp)
294     {
295       lport = strtol (port, &ep, 10);
296       if (ep == port || lport < 0 || lport > USHRT_MAX)
297 	{
298 	  free (*sa);
299 	  return -1;
300 	}
301       lport = htons (lport);
302     }
303   else
304     lport = sp->s_port;
305   if ((*sa)->sa_family == AF_INET)
306     ((struct sockaddr_in *)*sa)->sin_port = lport;
307   else
308     ((struct sockaddr_in6 *)*sa)->sin6_port = lport;
309   return 0;
310 #endif
311 }
312 
313 /*
314  * Convert a sockaddr to text. With zflag non-zero fill out with zeroes,
315  * i.e 10.0.0.10 --> "010.000.000.010"
316  */
317 int
318 sockaddr2text (struct sockaddr *sa, char **address, int zflag)
319 {
320   char buf[NI_MAXHOST];
321   char *token, *bstart, *ep;
322   int addrlen;
323   long val;
324   int i, j;
325 
326 #ifdef HAVE_GETNAMEINFO
327   if (getnameinfo (sa, sa->sa_len, buf, sizeof buf, 0, 0,
328 		   allow_name_lookups ? 0 : NI_NUMERICHOST))
329     return -1;
330 #else
331   switch (sa->sa_family)
332     {
333     case AF_INET:
334     case AF_INET6:
335       if (inet_ntop (sa->sa_family, sa->sa_data, buf, NI_MAXHOST - 1) == NULL)
336 	{
337 	  log_error ("sockaddr2text: inet_ntop (%d, %p, %p, %d) failed",
338 		     sa->sa_family, sa->sa_data, buf, NI_MAXHOST - 1);
339 	  return -1;
340 	}
341       buf[NI_MAXHOST - 1] = '\0';
342       break;
343 
344     default:
345       log_print ("sockaddr2text: unsupported protocol family %d\n",
346 		  sa->sa_family);
347       return -1;
348     }
349 #endif
350 
351   if (zflag == 0)
352     {
353       *address = malloc (strlen (buf) + 1);
354       if (!*address)
355 	return -1;
356       strcpy (*address, buf);
357     }
358   else
359     switch (sa->sa_family)
360       {
361       case AF_INET:
362 	addrlen = sizeof "000.000.000.000";
363 	*address = malloc (addrlen);
364 	if (!*address)
365 	  return -1;
366 	buf[addrlen] = '\0';
367 	bstart = buf;
368 	**address = '\0';
369 	while ((token = strsep (&bstart, ".")) != NULL)
370 	  {
371 	    if (strlen (*address) > 12)
372 	      {
373 		free (*address);
374 		return -1;
375 	      }
376 	    val = strtol (token, &ep, 10);
377 	    if (ep == token || val < 0 || val > UCHAR_MAX)
378 	      {
379 		free (*address);
380 		return -1;
381 	      }
382 	    sprintf (*address + strlen (*address), "%03ld", val);
383 	    if (bstart)
384 	      strcat (*address + strlen (*address), ".");
385 	  }
386 	break;
387 
388       case AF_INET6:
389 	/*
390 	 * XXX In the algorithm below there are some magic numbers we
391 	 * probably could give explaining names.
392 	 */
393 	addrlen = sizeof "0000:0000:0000:0000:0000:0000:0000:0000";
394 	*address = malloc (addrlen);
395 	if (!*address)
396 	  return -1;
397 
398 	for (i = 0, j = 0; i < 8; i++)
399 	  j += sprintf ((*address) + j, "%02x%02x:",
400 			((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[2 * i],
401 			((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[2 * i + 1]);
402 	(*address)[j - 1] = '\0';
403 	break;
404 
405       default:
406 	strcpy (*address, "<error>");
407       }
408 
409   return 0;
410 }
411 
412 /*
413  * sockaddr_len and sockaddr_data return the relevant sockaddr info depending
414  * on address family.  Useful to keep other code shorter(/clearer?).
415  */
416 int
417 sockaddr_len (struct sockaddr *sa)
418 {
419   switch (sa->sa_family)
420     {
421     case AF_INET6:
422       return sizeof ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr;
423     case AF_INET:
424       return sizeof ((struct sockaddr_in *)sa)->sin_addr.s_addr;
425     default:
426       log_print ("sockaddr_len: unsupported protocol family %d",
427 		 sa->sa_family);
428       return 0;
429     }
430 }
431 
432 u_int8_t *
433 sockaddr_data (struct sockaddr *sa)
434 {
435   switch (sa->sa_family)
436     {
437     case AF_INET6:
438       return (u_int8_t *)&((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr;
439     case AF_INET:
440       return (u_int8_t *)&((struct sockaddr_in *)sa)->sin_addr.s_addr;
441     default:
442       return 0;
443     }
444 }
445 
446 /*
447  * Convert network address to text. The network address does not need
448  * to be properly aligned.
449  */
450 void
451 util_ntoa (char **buf, int af, u_int8_t *addr)
452 {
453   struct sockaddr_storage from;
454   struct sockaddr *sfrom = (struct sockaddr *)&from;
455   socklen_t fromlen = sizeof from;
456   u_int32_t ip4_buf;
457 
458   memset (&from, 0, fromlen);
459   sfrom->sa_family = af;
460   switch (af)
461     {
462     case AF_INET:
463       sfrom->sa_len = sizeof (struct sockaddr_in);
464       memcpy (&ip4_buf, addr, sizeof (struct in_addr));
465       ((struct sockaddr_in *)sfrom)->sin_addr.s_addr = ip4_buf;
466       break;
467 
468     case AF_INET6:
469       sfrom->sa_len = sizeof (struct sockaddr_in6);
470       memcpy (sockaddr_data (sfrom), addr, sizeof (struct in6_addr));
471       break;
472     }
473 
474   if (sockaddr2text (sfrom, buf, 0))
475     {
476       log_print ("util_ntoa: "
477 		 "could not make printable address out of sockaddr %p", sfrom);
478       *buf = 0;
479     }
480 }
481 
482 /*
483  * Perform sanity check on files containing secret information.
484  * Returns -1 on failure, 0 otherwise.
485  * Also, if FILE_SIZE is a not a null pointer, store file size here.
486  */
487 int
488 check_file_secrecy (char *name, off_t *file_size)
489 {
490   struct stat st;
491 
492   if (stat (name, &st) == -1)
493     {
494       log_error ("check_file_secrecy: stat (\"%s\") failed", name);
495       return -1;
496     }
497   if (st.st_uid != geteuid () && st.st_uid != getuid ())
498     {
499       log_print ("check_file_secrecy: "
500 		 "not loading %s - file owner is not process user", name);
501       errno = EPERM;
502       return -1;
503     }
504   if ((st.st_mode & (S_IRWXG | S_IRWXO)) != 0)
505     {
506       log_print ("conf_file_secrecy: not loading %s - too open permissions",
507 		 name);
508       errno = EPERM;
509       return -1;
510     }
511 
512   if (file_size)
513     *file_size = st.st_size;
514 
515   return 0;
516 }
517