Massively cleaned up #include's, so they're in a consistent
[freeradius.git] / src / lib / misc.c
1 /*
2  * misc.c       Various miscellaneous functions.
3  *
4  * Version:     $Id$
5  *
6  *   This library is free software; you can redistribute it and/or
7  *   modify it under the terms of the GNU Lesser General Public
8  *   License as published by the Free Software Foundation; either
9  *   version 2.1 of the License, or (at your option) any later version.
10  *
11  *   This library is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  *   Lesser General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Lesser General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2006  The FreeRADIUS server project
21  */
22
23 #include        <freeradius-devel/ident.h>
24 RCSID("$Id$")
25
26 #include        <freeradius-devel/libradius.h>
27
28 #include        <ctype.h>
29 #include        <sys/file.h>
30 #include        <fcntl.h>
31
32 int             librad_dodns = 0;
33 int             librad_debug = 0;
34
35
36 /*
37  *      Return an IP address in standard dot notation
38  *
39  *      FIXME: DELETE THIS
40  */
41 const char *ip_ntoa(char *buffer, uint32_t ipaddr)
42 {
43         ipaddr = ntohl(ipaddr);
44
45         sprintf(buffer, "%d.%d.%d.%d",
46                 (ipaddr >> 24) & 0xff,
47                 (ipaddr >> 16) & 0xff,
48                 (ipaddr >>  8) & 0xff,
49                 (ipaddr      ) & 0xff);
50         return buffer;
51 }
52
53
54
55 /*
56  *      Internal wrapper for locking, to minimize the number of ifdef's
57  *
58  *      Lock an fd, prefer lockf() over flock()
59  */
60 int rad_lockfd(int fd, int lock_len)
61 {
62 #if defined(F_LOCK) && !defined(BSD)
63         return lockf(fd, F_LOCK, lock_len);
64 #elif defined(LOCK_EX)
65         return flock(fd, LOCK_EX);
66 #else
67         struct flock fl;
68         fl.l_start = 0;
69         fl.l_len = lock_len;
70         fl.l_pid = getpid();
71         fl.l_type = F_WRLCK;
72         fl.l_whence = SEEK_CUR;
73         return fcntl(fd, F_SETLKW, (void *)&fl);
74 #endif
75 }
76
77 /*
78  *      Internal wrapper for locking, to minimize the number of ifdef's
79  *
80  *      Lock an fd, prefer lockf() over flock()
81  *      Nonblocking version.
82  */
83 int rad_lockfd_nonblock(int fd, int lock_len)
84 {
85 #if defined(F_LOCK) && !defined(BSD)
86         return lockf(fd, F_TLOCK, lock_len);
87 #elif defined(LOCK_EX)
88         return flock(fd, LOCK_EX | LOCK_NB);
89 #else
90         struct flock fl;
91         fl.l_start = 0;
92         fl.l_len = lock_len;
93         fl.l_pid = getpid();
94         fl.l_type = F_WRLCK;
95         fl.l_whence = SEEK_CUR;
96         return fcntl(fd, F_SETLK, (void *)&fl);
97 #endif
98 }
99
100 /*
101  *      Internal wrapper for unlocking, to minimize the number of ifdef's
102  *      in the source.
103  *
104  *      Unlock an fd, prefer lockf() over flock()
105  */
106 int rad_unlockfd(int fd, int lock_len)
107 {
108 #if defined(F_LOCK) && !defined(BSD)
109         return lockf(fd, F_ULOCK, lock_len);
110 #elif defined(LOCK_EX)
111         return flock(fd, LOCK_UN);
112 #else
113         struct flock fl;
114         fl.l_start = 0;
115         fl.l_len = lock_len;
116         fl.l_pid = getpid();
117         fl.l_type = F_WRLCK;
118         fl.l_whence = SEEK_CUR;
119         return fcntl(fd, F_UNLCK, (void *)&fl);
120 #endif
121 }
122
123 /*
124  *      Return an interface-id in standard colon notation
125  */
126 char *ifid_ntoa(char *buffer, size_t size, uint8_t *ifid)
127 {
128         snprintf(buffer, size, "%x:%x:%x:%x",
129                  (ifid[0] << 8) + ifid[1], (ifid[2] << 8) + ifid[3],
130                  (ifid[4] << 8) + ifid[5], (ifid[6] << 8) + ifid[7]);
131         return buffer;
132 }
133
134
135 /*
136  *      Return an interface-id from
137  *      one supplied in standard colon notation.
138  */
139 uint8_t *ifid_aton(const char *ifid_str, uint8_t *ifid)
140 {
141         static const char xdigits[] = "0123456789abcdef";
142         const char *p, *pch;
143         int num_id = 0, val = 0, idx = 0;
144
145         for (p = ifid_str; ; ++p) {
146                 if (*p == ':' || *p == '\0') {
147                         if (num_id <= 0)
148                                 return NULL;
149
150                         /*
151                          *      Drop 'val' into the array.
152                          */
153                         ifid[idx] = (val >> 8) & 0xff;
154                         ifid[idx + 1] = val & 0xff;
155                         if (*p == '\0') {
156                                 /*
157                                  *      Must have all entries before
158                                  *      end of the string.
159                                  */
160                                 if (idx != 6)
161                                         return NULL;
162                                 break;
163                         }
164                         val = 0;
165                         num_id = 0;
166                         if ((idx += 2) > 6)
167                                 return NULL;
168                 } else if ((pch = strchr(xdigits, tolower(*p))) != NULL) {
169                         if (++num_id > 4)
170                                 return NULL;
171                         /*
172                          *      Dumb version of 'scanf'
173                          */
174                         val <<= 4;
175                         val |= (pch - xdigits);
176                 } else
177                         return NULL;
178         }
179         return ifid;
180 }
181
182
183 #ifndef HAVE_INET_PTON
184 static int inet_pton4(const char *src, struct in_addr *dst)
185 {
186         int octet;
187         unsigned int num;
188         const char *p, *off;
189         uint8_t tmp[4];
190         static const char digits[] = "0123456789";
191         
192         octet = 0;
193         p = src;
194         while (1) {
195                 num = 0;
196                 while (*p && ((off = strchr(digits, *p)) != NULL)) {
197                         num *= 10;
198                         num += (off - digits);
199                         
200                         if (num > 255) return 0;
201                         
202                         p++;
203                 }
204                 if (!*p) break;
205                 
206                 /*
207                  *      Not a digit, MUST be a dot, else we
208                  *      die.
209                  */
210                 if (*p != '.') {
211                         return 0;
212                 }
213
214                 tmp[octet++] = num;
215                 p++;
216         }
217         
218         /*
219          *      End of the string.  At the fourth
220          *      octet is OK, anything else is an
221          *      error.
222          */
223         if (octet != 3) {
224                 return 0;
225         }
226         tmp[3] = num;
227         
228         memcpy(dst, &tmp, sizeof(tmp));
229         return 1;
230 }
231
232
233 /* int
234  * inet_pton6(src, dst)
235  *      convert presentation level address to network order binary form.
236  * return:
237  *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
238  * notice:
239  *      (1) does not touch `dst' unless it's returning 1.
240  *      (2) :: in a full address is silently ignored.
241  * credit:
242  *      inspired by Mark Andrews.
243  * author:
244  *      Paul Vixie, 1996.
245  */
246 static int
247 inet_pton6(const char *src, unsigned char *dst)
248 {
249         static const char xdigits_l[] = "0123456789abcdef",
250                           xdigits_u[] = "0123456789ABCDEF";
251         u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
252         const char *xdigits, *curtok;
253         int ch, saw_xdigit;
254         u_int val;
255
256         memset((tp = tmp), 0, IN6ADDRSZ);
257         endp = tp + IN6ADDRSZ;
258         colonp = NULL;
259         /* Leading :: requires some special handling. */
260         if (*src == ':')
261                 if (*++src != ':')
262                         return (0);
263         curtok = src;
264         saw_xdigit = 0;
265         val = 0;
266         while ((ch = *src++) != '\0') {
267                 const char *pch;
268
269                 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
270                         pch = strchr((xdigits = xdigits_u), ch);
271                 if (pch != NULL) {
272                         val <<= 4;
273                         val |= (pch - xdigits);
274                         if (val > 0xffff)
275                                 return (0);
276                         saw_xdigit = 1;
277                         continue;
278                 }
279                 if (ch == ':') {
280                         curtok = src;
281                         if (!saw_xdigit) {
282                                 if (colonp)
283                                         return (0);
284                                 colonp = tp;
285                                 continue;
286                         }
287                         if (tp + INT16SZ > endp)
288                                 return (0);
289                         *tp++ = (u_char) (val >> 8) & 0xff;
290                         *tp++ = (u_char) val & 0xff;
291                         saw_xdigit = 0;
292                         val = 0;
293                         continue;
294                 }
295                 if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
296                     inet_pton4(curtok, tp) > 0) {
297                         tp += INADDRSZ;
298                         saw_xdigit = 0;
299                         break;  /* '\0' was seen by inet_pton4(). */
300                 }
301                 return (0);
302         }
303         if (saw_xdigit) {
304                 if (tp + INT16SZ > endp)
305                         return (0);
306                 *tp++ = (u_char) (val >> 8) & 0xff;
307                 *tp++ = (u_char) val & 0xff;
308         }
309         if (colonp != NULL) {
310                 /*
311                  * Since some memmove()'s erroneously fail to handle
312                  * overlapping regions, we'll do the shift by hand.
313                  */
314                 const int n = tp - colonp;
315                 int i;
316
317                 for (i = 1; i <= n; i++) {
318                         endp[- i] = colonp[n - i];
319                         colonp[n - i] = 0;
320                 }
321                 tp = endp;
322         }
323         if (tp != endp)
324                 return (0);
325         /* bcopy(tmp, dst, IN6ADDRSZ); */
326         memcpy(dst, tmp, IN6ADDRSZ);
327         return (1);
328 }
329
330 /*
331  *      Utility function, so that the rest of the server doesn't
332  *      have ifdef's around IPv6 support
333  */
334 int inet_pton(int af, const char *src, void *dst)
335 {
336         if (af == AF_INET) {
337                 return inet_pton4(src, dst);
338         }
339
340         if (af == AF_INET6) {
341                 return inet_pton6(src, dst);
342         }
343
344         return -1;
345 }
346 #endif
347
348
349 #ifndef HAVE_INET_NTOP
350 /*
351  *      Utility function, so that the rest of the server doesn't
352  *      have ifdef's around IPv6 support
353  */
354 const char *inet_ntop(int af, const void *src, char *dst, size_t cnt)
355 {
356         if (af == AF_INET) {
357                 const uint8_t *ipaddr = src;
358
359                 if (cnt <= INET_ADDRSTRLEN) return NULL;
360                 
361                 snprintf(dst, cnt, "%d.%d.%d.%d",
362                          ipaddr[0], ipaddr[1],
363                          ipaddr[2], ipaddr[3]);
364                 return dst;
365         }
366
367         /*
368          *      If the system doesn't define this, we define it
369          *      in missing.h
370          */
371         if (af == AF_INET6) {
372                 const struct in6_addr *ipaddr = src;
373                 
374                 if (cnt <= INET6_ADDRSTRLEN) return NULL;
375
376                 snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x",
377                          (ipaddr->s6_addr[0] << 8) | ipaddr->s6_addr[1],
378                          (ipaddr->s6_addr[2] << 8) | ipaddr->s6_addr[3],
379                          (ipaddr->s6_addr[4] << 8) | ipaddr->s6_addr[5],
380                          (ipaddr->s6_addr[6] << 8) | ipaddr->s6_addr[7],
381                          (ipaddr->s6_addr[8] << 8) | ipaddr->s6_addr[9],
382                          (ipaddr->s6_addr[10] << 8) | ipaddr->s6_addr[11],
383                          (ipaddr->s6_addr[12] << 8) | ipaddr->s6_addr[13],
384                          (ipaddr->s6_addr[14] << 8) | ipaddr->s6_addr[15]);
385                 return dst;
386         }
387
388         return NULL;            /* don't support IPv6 */
389 }
390 #endif
391
392
393 /*
394  *      Wrappers for IPv4/IPv6 host to IP address lookup.
395  *      This API returns only one IP address, of the specified
396  *      address family, or the first address (of whatever family),
397  *      if AF_UNSPEC is used.
398  */
399 int ip_hton(const char *src, int af, lrad_ipaddr_t *dst)
400 {
401         int error;
402         struct addrinfo hints, *ai = NULL, *res = NULL;
403
404         memset(&hints, 0, sizeof(hints));
405         hints.ai_family = af;
406
407         if ((error = getaddrinfo(src, NULL, &hints, &res)) != 0) {
408                 librad_log("ip_nton: %s", gai_strerror(error));
409                 return -1;
410         }
411
412         for (ai = res; ai; ai = ai->ai_next) {
413                 if ((af == ai->ai_family) || (af == AF_UNSPEC))
414                         break;
415         }
416
417         if (!ai) {
418                 librad_log("ip_hton failed to find requested information for host %.100s", src);
419                 freeaddrinfo(ai);
420                 return -1;
421         }
422
423         switch (ai->ai_family) {
424         case AF_INET :
425                 dst->af = AF_INET;
426                 memcpy(&dst->ipaddr, 
427                        &((struct sockaddr_in*)ai->ai_addr)->sin_addr, 
428                        sizeof(struct in_addr));
429                 break;
430                 
431         case AF_INET6 :
432                 dst->af = AF_INET6;
433                 memcpy(&dst->ipaddr, 
434                        &((struct sockaddr_in6*)ai->ai_addr)->sin6_addr, 
435                        sizeof(struct in6_addr));
436                 break;
437                 
438                 /* Flow should never reach here */
439         case AF_UNSPEC :
440         default :
441                 librad_log("ip_hton found unusable information for host %.100s", src);
442                 freeaddrinfo(ai);
443                 return -1;
444         }
445         
446         freeaddrinfo(ai);
447         return 0;
448 }
449
450 /*
451  *      Look IP addreses up, and print names (depending on DNS config)
452  */
453 const char *ip_ntoh(const lrad_ipaddr_t *src, char *dst, size_t cnt)
454 {
455         struct sockaddr_storage ss;
456         struct sockaddr_in  *s4;
457         int error, len;
458
459         /*
460          *      No DNS lookups
461          */
462         if (!librad_dodns) {
463                 return inet_ntop(src->af, &(src->ipaddr), dst, cnt);
464         }
465
466
467         memset(&ss, 0, sizeof(ss));
468         switch (src->af) {
469         case AF_INET :
470                 s4 = (struct sockaddr_in *)&ss;
471                 len    = sizeof(struct sockaddr_in);
472                 s4->sin_family = AF_INET;
473                 s4->sin_port = 0;
474                 memcpy(&s4->sin_addr, &src->ipaddr.ip4addr, 4);
475                 break;
476
477 #ifdef HAVE_STRUCT_SOCKADDR_IN6
478         case AF_INET6 :
479                 {
480                 struct sockaddr_in6 *s6;
481
482                 s6 = (struct sockaddr_in6 *)&ss;
483                 len    = sizeof(struct sockaddr_in6);
484                 s6->sin6_family = AF_INET6;
485                 s6->sin6_flowinfo = 0;
486                 s6->sin6_port = 0;
487                 memcpy(&s6->sin6_addr, &src->ipaddr.ip6addr, 16);
488                 break;
489                 }
490 #endif
491
492         default :
493                 return NULL;
494         }
495
496         if ((error = getnameinfo((struct sockaddr *)&ss, len, dst, cnt, NULL, 0,
497                                  NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
498                 librad_log("ip_ntoh: %s", gai_strerror(error));
499                 return NULL;
500         }
501         return dst;
502 }
503
504
505 static const char *hextab = "0123456789abcdef";
506
507 /*
508  *      hex2bin
509  *
510  *      We allow: hex == bin
511  */
512 int lrad_hex2bin(const char *hex, uint8_t *bin, int len)
513 {
514         int i;
515         char *c1, *c2;
516
517         for (i = 0; i < len; i++) {
518                 if(!(c1 = memchr(hextab, tolower((int) hex[i << 1]), 16)) ||
519                    !(c2 = memchr(hextab, tolower((int) hex[(i << 1) + 1]), 16)))
520                         break;
521                  bin[i] = ((c1-hextab)<<4) + (c2-hextab);
522         }
523
524         return i;
525 }
526
527
528 /*
529  *      bin2hex
530  *
531  *      If the output buffer isn't long enough, we have a buffer overflow.
532  */
533 void lrad_bin2hex(const uint8_t *bin, char *hex, int len)
534 {
535         int i;
536
537         for (i = 0; i < len; i++) {
538                 hex[0] = hextab[((*bin) >> 4) & 0x0f];
539                 hex[1] = hextab[*bin & 0x0f];
540                 hex += 2;
541                 bin++;
542         }
543         *hex = '\0';
544         return;
545 }
546
547
548 /*
549  *      So we don't have ifdef's in the rest of the code
550  */
551 #ifndef HAVE_CLOSEFROM
552 int closefrom(int fd)
553 {
554         int i;
555         int maxfd = 256;
556
557 #ifdef _SC_OPEN_MAX
558         maxfd = sysconf(_SC_OPEN_MAX);
559         if (maxfd < 0) {
560           maxfd = 256;
561         }
562 #endif
563
564         if (fd > maxfd) return 0;
565
566         /*
567          *      FIXME: return EINTR?
568          *
569          *      Use F_CLOSEM?
570          */
571         for (i = fd; i < maxfd; i++) {
572                 close(i);
573         }
574
575         return 0;
576 }
577 #endif