d4c5425c621101cf0f03f367b71acce282582c80
[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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
19  *
20  * Copyright 2000  The FreeRADIUS server project
21  */
22
23 static const char rcsid[] =
24 "$Id$";
25
26 #include        "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        "libradius.h"
43 #include        "missing.h"
44
45 int             librad_dodns = 0;
46 int             librad_debug = 0;
47
48
49 /*
50  *      Return a printable host name (or IP address in dot notation)
51  *      for the supplied IP address.
52  */
53 char *ip_hostname(char *buf, size_t buflen, uint32_t ipaddr)
54 {
55         struct          hostent *hp;
56 #ifdef GETHOSTBYADDRRSTYLE
57 #if (GETHOSTBYADDRRSTYLE == SYSVSTYLE) || (GETHOSTBYADDRRSTYLE == GNUSTYLE)
58         char buffer[2048];
59         struct hostent result;
60         int error;
61 #endif
62 #endif
63
64         /*
65          *      No DNS: don't look up host names
66          */
67         if (librad_dodns == 0) {
68                 ip_ntoa(buf, ipaddr);
69                 return buf;
70         }
71
72 #ifdef GETHOSTBYADDRRSTYLE
73 #if GETHOSTBYADDRRSTYLE == SYSVSTYLE
74         hp = gethostbyaddr_r((char *)&ipaddr, sizeof(struct in_addr), AF_INET, &result, buffer, sizeof(buffer), &error);
75 #elif GETHOSTBYADDRRSTYLE == GNUSTYLE
76         if (gethostbyaddr_r((char *)&ipaddr, sizeof(struct in_addr),
77                             AF_INET, &result, buffer, sizeof(buffer),
78                             &hp, &error) != 0) {
79                 hp = NULL;
80         }
81 #else
82         hp = gethostbyaddr((char *)&ipaddr, sizeof(struct in_addr), AF_INET);
83 #endif
84 #else
85         hp = gethostbyaddr((char *)&ipaddr, sizeof(struct in_addr), AF_INET);
86 #endif
87         if ((hp == NULL) ||
88             (strlen((char *)hp->h_name) >= buflen)) {
89                 ip_ntoa(buf, ipaddr);
90                 return buf;
91         }
92
93         strNcpy(buf, (char *)hp->h_name, buflen);
94         return buf;
95 }
96
97
98 /*
99  *      Return an IP address from a host
100  *      name or address in dot notation.
101  */
102 uint32_t ip_getaddr(const char *host)
103 {
104         struct hostent  *hp;
105         uint32_t         a;
106 #ifdef GETHOSTBYNAMERSTYLE
107 #if (GETHOSTBYNAMERSTYLE == SYSVSTYLE) || (GETHOSTBYNAMERSTYLE == GNUSTYLE)
108         struct hostent result;
109         int error;
110         char buffer[2048];
111 #endif
112 #endif
113
114         if ((a = ip_addr(host)) != htonl(INADDR_NONE))
115                 return a;
116
117 #ifdef GETHOSTBYNAMERSTYLE
118 #if GETHOSTBYNAMERSTYLE == SYSVSTYLE
119         hp = gethostbyname_r(host, &result, buffer, sizeof(buffer), &error);
120 #elif GETHOSTBYNAMERSTYLE == GNUSTYLE
121         if (gethostbyname_r(host, &result, buffer, sizeof(buffer),
122                             &hp, &error) != 0) {
123                 return htonl(INADDR_NONE);
124         }
125 #else
126         hp = gethostbyname(host);
127 #endif
128 #else
129         hp = gethostbyname(host);
130 #endif
131         if (hp == NULL) {
132                 return htonl(INADDR_NONE);
133         }
134
135         /*
136          *      Paranoia from a Bind vulnerability.  An attacker
137          *      can manipulate DNS entries to change the length of the
138          *      address.  If the length isn't 4, something's wrong.
139          */
140         if (hp->h_length != 4) {
141                 return htonl(INADDR_NONE);
142         }
143
144         memcpy(&a, hp->h_addr, sizeof(uint32_t));
145         return a;
146 }
147
148
149 /*
150  *      Return an IP address in standard dot notation
151  *
152  *      FIXME: DELETE THIS
153  */
154 const char *ip_ntoa(char *buffer, uint32_t ipaddr)
155 {
156         ipaddr = ntohl(ipaddr);
157
158         sprintf(buffer, "%d.%d.%d.%d",
159                 (ipaddr >> 24) & 0xff,
160                 (ipaddr >> 16) & 0xff,
161                 (ipaddr >>  8) & 0xff,
162                 (ipaddr      ) & 0xff);
163         return buffer;
164 }
165
166
167 /*
168  *      Return an IP address from
169  *      one supplied in standard dot notation.
170  *
171  *      FIXME: DELETE THIS
172  */
173 uint32_t ip_addr(const char *ip_str)
174 {
175         struct in_addr  in;
176
177         if (inet_aton(ip_str, &in) == 0)
178                 return htonl(INADDR_NONE);
179         return in.s_addr;
180 }
181
182
183 /*
184  *      Like strncpy, but always adds \0
185  */
186 char *strNcpy(char *dest, const char *src, int n)
187 {
188         char *p = dest;
189
190         while ((n > 1) && (*src)) {
191                 *(p++) = *(src++);
192
193                 n--;
194         }
195         *p = '\0';
196
197         return dest;
198 }
199
200 /*
201  * Lowercase a string
202  */
203 void rad_lowercase(char *str) {
204         char *s;
205
206         for (s=str; *s; s++)
207                 if (isupper((int) *s)) *s = tolower((int) *s);
208 }
209
210 /*
211  * Remove spaces from a string
212  */
213 void rad_rmspace(char *str) {
214         char *s = str;
215         char *ptr = str;
216
217   while(ptr && *ptr!='\0') {
218     while(isspace((int) *ptr))
219       ptr++;
220     *s = *ptr;
221     ptr++;
222     s++;
223   }
224   *s = '\0';
225 }
226
227 /*
228  *      Internal wrapper for locking, to minimize the number of ifdef's
229  *
230  *      Lock an fd, prefer lockf() over flock()
231  */
232 int rad_lockfd(int fd, int lock_len)
233 {
234 #if defined(F_LOCK) && !defined(BSD)
235         return lockf(fd, F_LOCK, lock_len);
236 #elif defined(LOCK_EX)
237         return flock(fd, LOCK_EX);
238 #else
239         struct flock fl;
240         fl.l_start = 0;
241         fl.l_len = lock_len;
242         fl.l_pid = getpid();
243         fl.l_type = F_WRLCK;
244         fl.l_whence = SEEK_CUR;
245         return fcntl(fd, F_SETLKW, (void *)&fl);
246 #endif
247 }
248
249 /*
250  *      Internal wrapper for locking, to minimize the number of ifdef's
251  *
252  *      Lock an fd, prefer lockf() over flock()
253  *      Nonblocking version.
254  */
255 int rad_lockfd_nonblock(int fd, int lock_len)
256 {
257 #if defined(F_LOCK) && !defined(BSD)
258         return lockf(fd, F_TLOCK, lock_len);
259 #elif defined(LOCK_EX)
260         return flock(fd, LOCK_EX | LOCK_NB);
261 #else
262         struct flock fl;
263         fl.l_start = 0;
264         fl.l_len = lock_len;
265         fl.l_pid = getpid();
266         fl.l_type = F_WRLCK;
267         fl.l_whence = SEEK_CUR;
268         return fcntl(fd, F_SETLK, (void *)&fl);
269 #endif
270 }
271
272 /*
273  *      Internal wrapper for unlocking, to minimize the number of ifdef's
274  *      in the source.
275  *
276  *      Unlock an fd, prefer lockf() over flock()
277  */
278 int rad_unlockfd(int fd, int lock_len)
279 {
280 #if defined(F_LOCK) && !defined(BSD)
281         return lockf(fd, F_ULOCK, lock_len);
282 #elif defined(LOCK_EX)
283         return flock(fd, LOCK_UN);
284 #else
285         struct flock fl;
286         fl.l_start = 0;
287         fl.l_len = lock_len;
288         fl.l_pid = getpid();
289         fl.l_type = F_WRLCK;
290         fl.l_whence = SEEK_CUR;
291         return fcntl(fd, F_UNLCK, (void *)&fl);
292 #endif
293 }
294
295 /*
296  *      Return an interface-id in standard colon notation
297  */
298 char *ifid_ntoa(char *buffer, size_t size, uint8_t *ifid)
299 {
300         snprintf(buffer, size, "%x:%x:%x:%x",
301                  (ifid[0] << 8) + ifid[1], (ifid[2] << 8) + ifid[3],
302                  (ifid[4] << 8) + ifid[5], (ifid[6] << 8) + ifid[7]);
303         return buffer;
304 }
305
306
307 /*
308  *      Return an interface-id from
309  *      one supplied in standard colon notation.
310  */
311 uint8_t *ifid_aton(const char *ifid_str, uint8_t *ifid)
312 {
313         static const char xdigits[] = "0123456789abcdef";
314         const char *p, *pch;
315         int num_id = 0, val = 0, idx = 0;
316
317         for (p = ifid_str; ; ++p) {
318                 if (*p == ':' || *p == '\0') {
319                         if (num_id <= 0)
320                                 return NULL;
321
322                         /*
323                          *      Drop 'val' into the array.
324                          */
325                         ifid[idx] = (val >> 8) & 0xff;
326                         ifid[idx + 1] = val & 0xff;
327                         if (*p == '\0') {
328                                 /*
329                                  *      Must have all entries before
330                                  *      end of the string.
331                                  */
332                                 if (idx != 6)
333                                         return NULL;
334                                 break;
335                         }
336                         val = 0;
337                         num_id = 0;
338                         if ((idx += 2) > 6)
339                                 return NULL;
340                 } else if ((pch = strchr(xdigits, tolower(*p))) != NULL) {
341                         if (++num_id > 4)
342                                 return NULL;
343                         /*
344                          *      Dumb version of 'scanf'
345                          */
346                         val <<= 4;
347                         val |= (pch - xdigits);
348                 } else
349                         return NULL;
350         }
351         return ifid;
352 }
353
354
355 #ifndef HAVE_INET_PTON
356 /*
357  *      Utility function, so that the rest of the server doesn't
358  *      have ifdef's around IPv6 support
359  */
360 int inet_pton(int af, const char *src, void *dst)
361 {
362         if (af != AF_INET) return -1; /* unsupported */
363
364         return inet_aton(src, dst);
365 }
366 #endif
367
368
369 #ifndef HAVE_INET_NTOP
370 /*
371  *      Utility function, so that the rest of the server doesn't
372  *      have ifdef's around IPv6 support
373  */
374 const char *inet_ntop(int af, const void *src, char *dst, size_t cnt)
375 {
376         if (af == AF_INET) {
377                 uint32_t ipaddr;
378
379                 if (cnt <= 15) return NULL;
380                 
381                 ipaddr = *(uint32_t *) src;
382                 ipaddr = ntohl(ipaddr);
383                 
384                 snprintf(dst, cnt, "%d.%d.%d.%d",
385                          (ipaddr >> 24) & 0xff,
386                          (ipaddr >> 16) & 0xff,
387                          (ipaddr >>  8) & 0xff,
388                          (ipaddr      ) & 0xff);
389                 return dst;
390         }
391
392         return NULL;            /* don't support IPv6 */
393 }
394 #endif
395
396
397 /*
398  *      Wrappers for IPv4/IPv6 host to IP address lookup.
399  *      This API returns only one IP address, of the specified
400  *      address family.
401  */
402 int ip_hton(const char *src, int af, lrad_ipaddr_t *dst)
403 {
404         struct hostent  *hp;
405 #ifdef GETHOSTBYNAMERSTYLE
406 #if (GETHOSTBYNAMERSTYLE == SYSVSTYLE) || (GETHOSTBYNAMERSTYLE == GNUSTYLE)
407         struct hostent result;
408         int error;
409         char buffer[2048];
410 #endif
411 #endif
412
413         if (af != AF_INET) return -1; /* only IPv4 for now */
414
415         dst->af = af;
416
417         /*
418          *      No DNS lookups, assume it's an IP address.
419          */
420         if (!librad_dodns) {
421                 return inet_pton(af, src, &dst->ipaddr.ip4addr);
422         }
423         
424 #ifdef GETHOSTBYNAMERSTYLE
425 #if GETHOSTBYNAMERSTYLE == SYSVSTYLE
426         hp = gethostbyname_r(src, &result, buffer, sizeof(buffer), &error);
427 #elif GETHOSTBYNAMERSTYLE == GNUSTYLE
428         if (gethostbyname_r(src, &result, buffer, sizeof(buffer),
429                             &hp, &error) != 0) {
430                 return htonl(INADDR_NONE);
431         }
432 #else
433         hp = gethostbyname(src);
434 #endif
435 #else
436         hp = gethostbyname(src);
437 #endif
438         if (!hp) return -1;
439
440         if (hp->h_addrtype != af) return -1; /* not the right address family */
441
442         /*
443          *      Paranoia from a Bind vulnerability.  An attacker
444          *      can manipulate DNS entries to change the length of the
445          *      address.  If the length isn't 4, something's wrong.
446          */
447         if (hp->h_length != 4) {
448                 return -1;
449         }
450
451         memcpy(&dst->ipaddr.ip4addr.s_addr, hp->h_addr,
452                sizeof(dst->ipaddr.ip4addr.s_addr));
453         return 0;
454         
455 }
456
457 /*
458  *      Look IP addreses up, and print names (depending on DNS config)
459  */
460 const char *ip_ntoh(const lrad_ipaddr_t *src, char *dst, size_t cnt)
461 {
462         struct          hostent *hp;
463 #ifdef GETHOSTBYADDRRSTYLE
464 #if (GETHOSTBYADDRRSTYLE == SYSVSTYLE) || (GETHOSTBYADDRRSTYLE == GNUSTYLE)
465         char buffer[2048];
466         struct hostent result;
467         int error;
468 #endif
469 #endif
470
471         /*
472          *      No DNS: don't look up host names
473          */
474         if (!librad_dodns) {
475                 return inet_ntop(src->af, &src->ipaddr, dst, cnt);
476         }
477
478         if (src->af != AF_INET) return NULL; /* invalid */
479
480 #ifdef GETHOSTBYADDRRSTYLE
481 #if GETHOSTBYADDRRSTYLE == SYSVSTYLE
482         hp = gethostbyaddr_r((const char *)&src->ipaddr.ip4addr.s_addr,
483                              sizeof(src->ipaddr.ip4addr.s_addr),
484                              src->af, &result, buffer, sizeof(buffer), &error);
485 #elif GETHOSTBYADDRRSTYLE == GNUSTYLE
486         if (gethostbyaddr_r((const char *)&src->ipaddr.ip4addr.s_addr,
487                             sizeof(src->ipaddr.ip4addr.s_addr),
488                             src->af, &result, buffer, sizeof(buffer),
489                             &hp, &error) != 0) {
490                 hp = NULL;
491         }
492 #else
493         hp = gethostbyaddr((const char *)&src->ipaddr.ip4addr.s_addr,
494                            sizeof(src->ipaddr.ip4addr.s_addr), src->af);
495 #endif
496 #else
497         hp = gethostbyaddr((const char *)&src->ipaddr.ip4addr.s_addr,
498                            sizeof(src->ipaddr.ip4addr.s_addr), src->af);
499 #endif
500         if ((hp == NULL) ||
501             (strlen((char *)hp->h_name) >= cnt)) {
502                 return inet_ntop(src->af, &src->ipaddr, dst, cnt);
503         }
504
505         strNcpy(dst, (char *)hp->h_name, cnt);
506         return dst;
507 }
508
509 static const char *hextab = "0123456789abcdef";
510
511 /*
512  *      hex2bin
513  *
514  *      We allow: hex == bin
515  */
516 int lrad_hex2bin(const unsigned char *hex, unsigned char *bin, int len)
517 {
518         int i;
519         char *c1, *c2;
520
521         for (i = 0; i < len; i++) {
522                 if(!(c1 = memchr(hextab, tolower((int) hex[i << 1]), 16)) ||
523                    !(c2 = memchr(hextab, tolower((int) hex[(i << 1) + 1]), 16)))
524                         break;
525                  bin[i] = ((c1-hextab)<<4) + (c2-hextab);
526         }
527
528         return i;
529 }
530
531
532 /*
533  *      bin2hex
534  *
535  *      If the output buffer isn't long enough, we have a buffer overflow.
536  */
537 void lrad_bin2hex(const unsigned char *bin, unsigned char *hex, int len)
538 {
539         int i;
540
541         for (i = 0; i < len; i++) {
542                 hex[0] = hextab[((*bin) >> 4) & 0x0f];
543                 hex[1] = hextab[*bin & 0x0f];
544                 hex += 2;
545                 bin++;
546         }
547         *hex = '\0';
548         return;
549 }