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