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